home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #2 / Monster Media No. 2 (Monster Media)(1994).ISO / utils1 / 2m21src.zip / 2M-ABIOS.ASM next >
Assembly Source File  |  1994-05-31  |  119KB  |  2,884 lines

  1.  
  2. ;*********************************************************************
  3. ;*                                                                   *
  4. ;*      2M-ABIOS 1.2  -  (C) Mayo 1994 Ciriaco García de Celis.      *
  5. ;*                                                                   *
  6. ;*          Código para emular al 100% la BIOS AMI de 1993.          *
  7. ;*                                                                   *
  8. ;*     Si el ordenador posee disco duro, la INT 40h controla los     *
  9. ;*     accesos a disquete. Desviar esta interrupción en lugar de     *
  10. ;*     la  INT 13h  permite que este programa tome el control de     *
  11. ;*     las disqueteras antes que cualquier otro  (incluso aunque     *
  12. ;*     se instale después) y además permite seguir trabajando al     *
  13. ;*     código del DOS que, desde INT 13h, soluciona el cruce con     *
  14. ;*     las fronteras de DMA antes de invocar a la INT 40h.           *
  15. ;*                                                                   *
  16. ;*     Si el ordenador no utilizase la  INT 40h en los accesos a     *
  17. ;*     las disqueteras se desvía INT 13h y se cuelga este código     *
  18. ;*     de la misma, cuidando evitar un cruce con el DMA a través     *
  19. ;*     de un buffer intermedio auxiliar si es preciso.               *
  20. ;*                                                                   *
  21. ;*     Ensamblar con TASM /m5 y linkar con TLINK para obtener un     *
  22. ;*     fichero EXE que se instala con DEVICE desde el CONFIG.SYS     *
  23. ;*                                                                   *
  24. ;*********************************************************************
  25.  
  26.                .286
  27.  
  28. ; ------------ Macros de propósito general.
  29.  
  30. XPUSH          MACRO regmem            ; apilar lista de registros
  31.                  IRP rm, <regmem>
  32.                    PUSH rm
  33.                  ENDM
  34.                ENDM
  35.  
  36. XPOP           MACRO regmem            ; desapilar lista de registros
  37.                  IRP rm, <regmem>
  38.                    POP rm
  39.                  ENDM
  40.                ENDM
  41.  
  42. ; ************ Inicio del área residente.
  43.  
  44. _PRINCIPAL     SEGMENT
  45.                ASSUME CS:_PRINCIPAL, DS:_PRINCIPAL
  46.  
  47.                ORG   0
  48.  
  49. ini_residente  EQU   $
  50.  
  51.                DD    -1           ; encadenamiento con otros drivers
  52. tipo_drive     DW    8000h        ; palabra de atributo:
  53.                                   ; bit 15 a 1: dispositivo caracteres
  54.                                   ; bit 14 a 0: sin control IOCTL
  55.                DW    estrategia   ; rutina de estrategia
  56.                DW    interrupcion ; rutina de interrupción
  57.                DB    "2M-BIOS$"   ; nombre del dispositivo
  58.  
  59. estrategia     PROC  FAR
  60.                MOV   CS:pcab_pet_segm,ES
  61.                MOV   CS:pcab_pet_desp,BX
  62.                RET
  63. estrategia     ENDP
  64.  
  65. interrupcion   PROC  FAR
  66.                CALL  main  ; tras instalar: XPUSH <DS, BX> y MOV BX,??
  67. pcab_pet_segm  DW    ?
  68.                MOV   DS,BX
  69.                DB    0BBh  ; opcode de MOV BX,??
  70. pcab_pet_desp  DW    ?
  71.                MOV   WORD PTR [BX+3],8103h  ; código de error
  72.                XPOP  <BX, DS>
  73.                RET
  74. interrupcion   ENDP
  75.  
  76. ; ****************************************
  77. ; *                                      *
  78. ; *   D A T O S    R E S I D E N T E S   *
  79. ; *                                      *
  80. ; ****************************************
  81.  
  82. ; ------------ Identificación estandarizada del programa.
  83.  
  84. program_id     LABEL BYTE
  85. segmento_real  DW    0   ; segmento real donde será cargado
  86. offset_real    DW    0   ; offset real     "     "     "
  87. longitud_total DW    0   ; zona de memoria ocupada (párrafos)
  88. info_extra     DB    03h ; bits 0, 1 y 2-> 000: normal, con PSP
  89.                          ;                 001: bloque UMB XMS
  90.                          ;                 010: *.SYS
  91.                          ;                 011: *.SYS formato EXE
  92.                          ; bit 7 a 1: «extension_id» definida
  93. multiplex_id   DB    0   ; número Multiplex de este TSR
  94. vectores_id    DW    tabla_vectores
  95. extension_id   DW    0
  96.                DB    "*##*"
  97. autor_nom_ver  DB    "CiriSOFT:2M-ABIOS:1.2",0
  98.  
  99.                DB    2  ; número de vectores de interrupción usados
  100. tabla_vectores EQU   $
  101.                DB    2Fh           ; INT 2Fh
  102. ant_int2F      LABEL DWORD         ; dirección original
  103. ant_int2F_off  DW    0
  104. ant_int2F_seg  DW    0
  105.                DB    40h           ; INT 40h
  106. ant_int40      LABEL DWORD         ; dirección original
  107. ant_int40_off  DW    0
  108. ant_int40_seg  DW    0
  109.                DB    13h           ; INT 13h podría llegar a usarse
  110. ant_int13      LABEL DWORD
  111. ant_int13_off  DW    0
  112. ant_int13_seg  DW    0
  113.  
  114. ; ***************************************
  115. ; *                                     *
  116. ; *   C O D I G O   R E S I D E N T E   *
  117. ; *                                     *
  118. ; ***************************************
  119.  
  120. ; ------------ Rutina de gestión de INT 2Fh.
  121.  
  122. ges_int2F      PROC  FAR
  123.                STI
  124.                CMP   AH,CS:multiplex_id
  125.                JE    preguntan
  126.                JMP   CS:ant_int2F      ; saltar al gestor de INT 2Fh
  127. preguntan:     CMP   DI,1992h
  128.                JNE   ret_no_info       ; no llama alguien del convenio
  129.                MOV   AX,ES
  130.                CMP   AX,1492h
  131.                JNE   ret_no_info       ; no llama alguien del convenio
  132.                PUSH  CS
  133.                POP   ES                ; sí llama: darle información
  134.                LEA   DI,autor_nom_ver
  135. ret_no_info:   MOV   AX,0FFFFh         ; "entrada multiplex en uso"
  136.                IRET
  137. ges_int2F      ENDP
  138.  
  139. ; ------------ Rutina de control de INT 40h.
  140.  
  141. r_flags        EQU   WORD PTR [BP+18h] ; constantes para parámetros
  142. r_flags_l      EQU   BYTE PTR [BP+18h]
  143. r_flags_h      EQU   BYTE PTR [BP+19h]
  144. r_ax           EQU   WORD PTR [BP+12h]
  145. r_al           EQU   BYTE PTR [BP+12h]
  146. r_ah           EQU   BYTE PTR [BP+13h]
  147. r_cx           EQU   WORD PTR [BP+10h]
  148. r_cl           EQU   BYTE PTR [BP+10h]
  149. r_ch           EQU   BYTE PTR [BP+11h]
  150. r_dx           EQU   WORD PTR [BP+0Eh]
  151. r_dl           EQU   BYTE PTR [BP+0Eh]
  152. r_dh           EQU   BYTE PTR [BP+0Fh]
  153. r_bx           EQU   WORD PTR [BP+0Ch]
  154. r_bl           EQU   BYTE PTR [BP+0Ch]
  155. r_bh           EQU   BYTE PTR [BP+0Dh]
  156. r_bp           EQU   WORD PTR [BP+0Ah]
  157. r_si           EQU   WORD PTR [BP+08h]
  158. r_di           EQU   WORD PTR [BP+06h]
  159. r_ds           EQU   WORD PTR [BP+04h]
  160. r_es           EQU   WORD PTR [BP+02h]
  161.  
  162. ges_int40      PROC
  163.                STI
  164.                CLD
  165.                PUSH  AX
  166.                PUSH  CX
  167.                PUSH  DX
  168.                PUSH  BX
  169.                PUSH  BP
  170.                PUSH  SI
  171.                PUSH  DI
  172.                PUSH  DS
  173.                PUSH  ES
  174.                PUSH  BP
  175.                MOV   BP,SP
  176.                PUSH  40h
  177.                POP   DS
  178.                PUSH  AX
  179.                MOV   AL,AH
  180.                CMP   AL,18h
  181.                JA    mal_funcion
  182.                CMP   AL,5
  183.                JBE   func_oper
  184.                CMP   AL,8
  185.                JNE   func_aux?
  186.                MOV   AL,6
  187.                JMP   func_oper
  188. func_aux?:     CMP   AL,15h
  189.                JB    mal_funcion
  190.                SUB   AL,0Eh
  191. func_oper:     CBW
  192.                MOV   DI,AX
  193.                POP   AX
  194.                SHL   DI,1
  195.                JMP   CS:tab_jmp[DI]    ; ejecutar función
  196. main_exit:     MOV   AL,AH             ; preservar resultado
  197.                LAHF                    ; preservar flags
  198.                PUSH  AX
  199.                PUSH  40h
  200.                POP   DS
  201.                MOV   AL,r_dl           ; DL a la llamada (unidad)
  202.                CMP   AL,1
  203.                JA    u_det             ; unidad incorrecta
  204.                XOR   AH,AH
  205.                MOV   BX,90h
  206.                ADD   BX,AX             ; [BX] -> estado físico unidad
  207.                TEST  BYTE PTR DS:[BX],10h  ; ¿densidad determinada?
  208.                JZ    u_det                 ; no
  209.                MOV   DL,4                  ; sí
  210.                MUL   DL
  211.                MOV   CL,AL                 
  212.                SHL   DL,CL
  213.                OR    DS:[8Fh],DL           ; unidad determinada
  214. u_det:         POP   AX
  215.                SAHF                    ; recuperar flags
  216.                MOV   AH,AL             ; recuperar resultado
  217. exit_i40:      MOV   r_ah,AH           ; AH para la salida del IRET
  218.                MOV   AX,201H           ; STI + STC en flags
  219.                JC    set_err           ; hay error
  220.                AND   r_flags_l,0FEH    ; CLC (si no hay error)
  221.                DEC   AX                ; dejar sólo STI
  222. set_err:       OR    r_flags,AX        ; flags a la salida del IRET
  223.                POP   BP
  224.                POP   ES
  225.                POP   DS
  226.                POP   DI
  227.                POP   SI
  228.                POP   BP
  229.                POP   BX
  230.                POP   DX
  231.                POP   CX
  232.                POP   AX                ; registros con resultado
  233.                IRET
  234. ges_int40      ENDP
  235.  
  236. mal_funcion:   POP   AX
  237.                MOV   AH,1              ; función/parámetro incorrecto
  238.                MOV   DS:[41h],AH       ; código de error
  239.                STC                     ; condición de error
  240.                JMP   exit_i40
  241.  
  242. ; ------------ Función 0: Resetear el sistema de disco.
  243.  
  244. reset          PROC
  245.                CALL  full_init         ; inicialización plena
  246.                MOV   DS:[41h],AH       ; código de error
  247.                MOV   AL,AH             ; preservar código
  248.                LAHF                    ; preservar flags
  249.                PUSH  AX
  250.                PUSH  DS
  251.                XOR   SI,SI
  252.                MOV   DS,SI
  253.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  254.                MOV   CL,[SI+2]
  255.                POP   DS
  256.                MOV   DS:[40h],CL       ; tics para detención motor
  257.                POP   AX
  258.                SAHF
  259.                MOV   AH,AL             ; restaurado código y flags
  260.                JMP   exit_i40
  261. reset          ENDP
  262.  
  263. ; ------------ Inicialización plena.
  264.  
  265. full_init      PROC
  266.                AND   BYTE PTR DS:[3Eh],0F0h   ; futuro recalibramiento
  267.                JMP   init_fdc                 ; inicializar FDC
  268. fdc_init:      JC    init_end
  269.                JMP   send_specify             ; enviar specify
  270. specify_sent:  JC    init_end
  271.                XOR   AH,AH                    ; no hay error
  272. init_end:      RET
  273. full_init      ENDP
  274.  
  275. ; ------------ Función 1: Obtener resultado de la última operación.
  276.  
  277. get_status     PROC
  278.                MOV   AH,DS:[41h]
  279.                OR    AH,AH
  280.                JZ    no_err
  281.                STC
  282. no_err:        JMP   exit_i40
  283. get_status     ENDP
  284.  
  285. ; ------------ Función 15h: Obtener el tipo de disco.
  286.  
  287. get_disk_type  PROC
  288.                CMP   DL,1
  289.                JBE   gdt_ok
  290.                MOV   AH,1              ; función/parámetro incorrecto
  291.                STC
  292.                MOV   DS:[41h],AH       ; código de error
  293.                JMP   gdt_exit
  294. gdt_ok:        MOV   BX,90h
  295.                XOR   DH,DH
  296.                ADD   BX,DX             ; [BX] -> estado físico unidad
  297.                MOV   BL,[BX]           ; estado físico de la unidad
  298.                OR    BL,BL
  299.                JNZ   gdt_posible
  300.                XOR   AH,AH             ; no existe tal unidad
  301.                JMP   gdt_bye
  302. gdt_posible:   AND   BL,7
  303.                JZ    gdt_without       ; 360K
  304.                CMP   BL,3
  305.                JE    gdt_without       ; 360K
  306.                MOV   AH,2
  307.                JMP   gdt_bye           ; con soporte cambio de línea
  308. gdt_without:   MOV   AH,1              ; sin soporte cambio de línea
  309. gdt_bye:       CLC
  310.                MOV   BYTE PTR DS:[41h],0  ; siempre sin error
  311. gdt_exit:      JMP   main_exit
  312. get_disk_type  ENDP
  313.  
  314. ; ------------ Función 17h: Establecer tipo de soporte para formateo.
  315.  
  316. set_type_fmt   PROC
  317.                XOR   AH,AH
  318.                CMP   DL,1
  319.                JBE   set_tp
  320. set_tp_bad_p:  MOV   AH,1              ; función/parámetro incorrecto
  321. set_tp_err:    MOV   DS:[41h],AH       ; código de error
  322.                STC
  323.                JMP   set_tp_exit
  324. set_tp:        CMP   AL,0              ; validar parámetro
  325.                JE    set_tp_bad_p
  326.                CMP   AL,4
  327.                JA    set_tp_bad_p
  328.                MOV   BX,90h
  329.                XOR   DH,DH
  330.                ADD   BX,DX             ; [BX] -> estado físico unidad
  331.                CMP   AL,1              ; ¿360K en 360K?
  332.                JNE   set_tp_n360
  333.                MOV   BYTE PTR DS:[BX],93h  ; actualizar variable tipo
  334.                MOV   BYTE PTR DS:[41h],0   ; anular errores previos
  335.                JMP   set_tp_t_exit
  336. set_tp_n360:   MOV   CX,AX
  337.                PUSH  BX
  338.                CALL  motor_on              ; arrancar motor
  339.                POP   SI
  340.                PUSH  SI
  341.                CALL  read_disk_chg         ; ¿cambio de disco?
  342.                POP   BX
  343.                CMP   AH,6                  ; (0: no, 6: sí)
  344.                JBE   set_tp_cd             ; haya cambio o no
  345.                CMP   AH,80h
  346.                JNE   set_tp_cd             ; sí existe disco
  347.                CMP   BYTE PTR DS:[BX],97h  ; ¿250 Kbps y no es 5.25?
  348.                JE    set_tp_err            ; error
  349.                MOV   BYTE PTR DS:[BX],61h  ; 300 Kbps, try 360 en 1.2
  350.                JMP   set_tp_err            ; error
  351. set_tp_cd:     CMP   CL,4                  ; ¿720K en 720K?
  352.                JNE   set_tp_n720           ; no
  353.                MOV   BYTE PTR DS:[BX],97h  ; actualizar variable tipo
  354.                JMP   set_tp_t_exit
  355. set_tp_n720:   CMP   CL,2                  ; ¿360K en 1.2M?
  356.                JNE   set_tp_ndd            ; no
  357.                MOV   BYTE PTR DS:[BX],74h  ; actualizar variable tipo
  358.                JMP   set_tp_t_exit
  359. set_tp_ndd:    MOV   BYTE PTR DS:[BX],15h  ; 1.2M en 1.2M
  360. set_tp_t_exit: OR    AH,AH                 ; comprobar posible error
  361.                JNZ   set_tp_err
  362.                MOV   BYTE PTR DS:[41h],0
  363. set_tp_exit:   JMP   main_exit
  364. set_type_fmt   ENDP
  365.  
  366. ; ------------ Función 16h: Detectar cambio de disco.
  367.  
  368. detect_change  PROC
  369.                CMP   DL,1
  370.                JBE   det_ch
  371.                MOV   AH,1              ; función/parámetro incorrecto
  372. det_ch_r_err:  STC
  373.                JMP   det_ch_end
  374. det_ch:        XOR   DH,DH
  375.                MOV   BX,90h
  376.                ADD   BX,DX               ; [BX] -> estado físico
  377.                CMP   BYTE PTR DS:[BX],0  ; ¿estado indeterminado?...
  378.                MOV   AH,80h              ; "unidad no preparada"
  379.                JE    det_ch_r_err        ; ...en efecto
  380.                MOV   AH,[BX]
  381.                AND   AH,7
  382.                JZ    det_ch_yes          ; 360K en 360K, no es posible
  383.                CMP   AH,3
  384.                JNE   det_ch_calc         ; no es 360K en 360K
  385. det_ch_yes:    MOV   AH,6                ; hay cambio (o desconocido)
  386.                STC
  387.                JMP   det_ch_end
  388. det_ch_calc:   CALL  motor_on          ; arrancar motor
  389.                MOV   DX,3F7h
  390.                IN    AL,DX             ; leer línea de cambio de disco
  391.                SHL   AL,1
  392.                JC    det_ch_yes        ; hay cambio de disco
  393.                XOR   AH,AH             ; no lo hay
  394. det_ch_end:    MOV   DS:[41h],AH       ; actualizar código de error
  395.                PUSH  AX
  396.                PUSH  SI
  397.                PUSH  DS
  398.                MOV   SI,0
  399.                MOV   DS,SI
  400.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  401.                MOV   AL,[SI+2]
  402.                POP   DS
  403.                MOV   DS:[40h],AL       ; tiempo detención motor
  404.                POP   SI
  405.                POP   AX
  406.                JMP   main_exit
  407. detect_change  ENDP
  408.  
  409. ; ------------ Funciones 2, 3 y 4: Leer, escribir y verificar.
  410.  
  411. read_wr_verify PROC
  412.                CMP   DL,1
  413.                JBE   rwv_posible
  414.                MOV   AH,1              ; función/parámetro incorrecto
  415. rwv_err:       MOV   DS:[41h],AH       ; código de error
  416.                XOR   AL,AL
  417.                STC
  418.                JMP   rwv_exit
  419. rwv_posible:   MOV   SI,90h
  420.                PUSH  DX
  421.                XOR   DH,DH
  422.                ADD   SI,DX               ; [SI] -> estado físico
  423.                CMP   BYTE PTR DS:[SI],0  ; ¿estado indeterminado?...
  424.                POP   DX
  425.                JNE   rwv_state_ok      ; no
  426.                PUSH  AX
  427.                CALL  get_drive_type    ; obtener tipo disquetera en AL
  428.                JZ    rwv_type_ok       ; ha resultado posible
  429.                POP   AX
  430. rwv_not_ready: MOV   AH,80h            ; "unidad no preparada"
  431.                JMP   rwv_err
  432. rwv_type_ok:   OR    AL,AL             ; ¿existe la unidad?
  433.                POP   AX
  434.                JZ    rwv_not_ready     ; no existe esa unidad
  435.                MOV   BYTE PTR DS:[SI],2    ; probando 1.2M en 1.2M
  436. rwv_state_ok:  MOV   DI,3Fh
  437.                AND   BYTE PTR DS:[DI],7Fh  ; operación Read/Verify
  438.                CMP   AH,3                  ; ¿operación de escritura?
  439.                JNE   rwv_nowr
  440.                OR    BYTE PTR DS:[DI],80h  ; operación Write/Format
  441. rwv_nowr:      PUSH  SI
  442.                CALL  get_drive_type    ; obtener tipo disquetera en AL
  443.                JNZ   rwv_media_ok
  444.                CMP   AL,1
  445.                JE    rwv_set360            ; es de 360K
  446.                CMP   AL,3
  447.                JNE   rwv_media_ok          ; no es de 720K
  448.                MOV   BYTE PTR DS:[SI],97h    ; forzar medio de 720K
  449.                JMP   rwv_media_ok
  450. rwv_set360:    MOV   BYTE PTR DS:[SI],93h    ; forzar medio de 360K
  451. rwv_media_ok:  CALL  motor_on          ; arrancar motores
  452.                CALL  read_disk_chg     ; leer línea de cambio de disco
  453.                POP   SI
  454.                JNC   rwv_no_dschg      ; no hay cambio de disco
  455. rwv_end_err:   CALL  end_io_access
  456.                JMP   rwv_err
  457. rwv_no_dschg:  TEST  BYTE PTR DS:[SI],10h  ; ¿densidad determinada?
  458.                JNZ   rwv_set_rate          ; en efecto
  459.                CALL  detect_media          ; pues determinarla
  460.                JC    rwv_end_err           ; problemas
  461.                JMP   rwv_dens_ok
  462. rwv_set_rate:  CALL  select_rate       ; seleccionar la velocidad
  463. rwv_dens_ok:   MOV   SI,90h
  464.                PUSH  DX
  465.                XOR   DH,DH
  466.                ADD   SI,DX             ; [SI] -> estado físico unidad
  467.                POP   DX
  468.                MOV   AX,0AF03H                ; AF byte 0 specify 2.88
  469.                CMP   BYTE PTR DS:[SI],0D7h    ; ¿2.88M?
  470.                JE    rwv_spec_ok              ; así es
  471.                MOV   AX,0DF03h                ; DF para 360/1.2/720
  472.                CMP   BYTE PTR DS:[SI],17h     ; ¿1.44M?
  473.                JNE   rwv_spec_ok              ; no
  474.                MOV   AH,0BFh                  ; sí
  475. rwv_spec_ok:   MOV   SI,AX                    ; SI 0-7: orden specify
  476.                MOV   DI,2                     ; DI 0-7: byte 1 specify
  477.                MOV   CH,3                     ; comando de 3 bytes
  478.                OR    BYTE PTR DS:[3Eh],80h    ; no esperar INT
  479.                CALL  exec_cmd
  480.                JC    rwv_end_err       ; fallo
  481.                MOV   AX,r_ax
  482.                XOR   AH,AH
  483.                PUSH  DS
  484.                XOR   SI,SI
  485.                MOV   DS,SI
  486.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  487.                MOV   CL,[SI+3]         ; bytes/sector
  488.                SHL   AL,CL             ; multiplicar por nº sectores
  489.                MOV   CL,80h
  490.                MUL   CL                ; y por 128
  491.                POP   DS
  492.                DEC   AX                ; un byte menos...
  493.                MOV   CX,AX             ; ...cuenta para el DMA
  494.                CALL  eval_dir_DMA
  495.                JNC   rwv_dma_ok        ; no hay problemas con el DMA
  496.                MOV   CX,r_cx           ; restaurar CX
  497.                JMP   rwv_end_err       ; problemas con el DMA
  498. rwv_dma_ok:    MOV   AX,r_ax
  499.                CMP   AH,2              ; ¿operación de lectura?
  500.                JNE   rwv_no_read
  501.                MOV   AH,46h            ; byte de modo DMA para lectura
  502.                JMP   rwv_dma_set
  503. rwv_no_read:   CMP   AH,3              ; ¿escritura?
  504.                MOV   AH,4Ah            ; modo DMA para escritura
  505.                JZ    rwv_dma_set
  506.                MOV   AH,42h            ; modo DMA para verificación
  507. rwv_dma_set:   CALL  set_dma           ; preparar DMA
  508.                MOV   AX,r_ax
  509.                MOV   CX,r_cx           ; restaurar parámetros
  510.                JMP   perform_io        ; efectuar E/S
  511. io_performed:  CALL  end_io_access
  512.                OR    AL,AL
  513.                JZ    rwv_end
  514.                SUB   BL,CL             ; próximo sector-sector inicial
  515.                MOV   AL,BL             ; nº sectores transferidos
  516. rwv_end:       MOV   AH,DS:[41h]
  517.                OR    AH,AH             ; ¿error?
  518.                JZ    rwv_exit
  519.                STC                     ; señalizar error
  520. rwv_exit:      MOV   r_al,AL           ; nº sectores transferidos
  521.                JMP   main_exit
  522. read_wr_verify ENDP
  523.  
  524. ; ------------ Función 5: Formatear pista.
  525.  
  526. format_track   PROC
  527.                CMP   DL,1
  528.                JBE   fmt_do
  529.                MOV   AH,1              ; función/parámetro incorrecto
  530. fmt_exit_err:  MOV   DS:[41h],AH       ; código de error
  531.                STC
  532.                JMP   main_exit
  533. fmt_do:        MOV   SI,90h
  534.                PUSH  DX
  535.                XOR   DH,DH
  536.                ADD   SI,DX             ; [SI] -> estado físico unidad
  537.                POP   DX
  538.                CMP   BYTE PTR DS:[SI],0
  539.                MOV   AH,80h            ; "unidad no preparada"
  540.                JE    fmt_exit_err      ; indeterminado
  541.                MOV   DI,3Fh
  542.                OR    BYTE PTR DS:[DI],80h  ; no esperar INT
  543.                CALL  motor_on          ; arrancar motores
  544.                CALL  read_disk_chg     ; leer línea de cambio de disco
  545.                JNC   fmt_posible       ; no hay cambio de disco
  546. fmt_err:       CALL  end_io_access
  547.                JMP   fmt_exit_err      ; error
  548. fmt_posible:   CALL  select_rate       ; seleccionar la velocidad
  549.                CALL  send_specify      ; enviar comando specify
  550.                PUSH  DS
  551.                XOR   SI,SI
  552.                MOV   DS,SI
  553.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  554.                MOV   AL,[SI+4]         ; sectores por pista
  555.                POP   DS
  556.                XOR   AH,AH
  557.                MOV   CL,4
  558.                MUL   CL                ; 4 bytes para cada uno
  559.                MOV   CX,AX
  560.                DEC   CX                ; un byte menos...
  561.                CALL  eval_dir_DMA      ; ...cuenta para el DMA
  562.                JC    fmt_err           ; cruza frontera de DMA
  563.                MOV   AH,4Ah            ; modo DMA para escritura
  564.                CALL  set_dma           ; preparar DMA
  565.                MOV   CX,r_cx           ; restaurar CX
  566.                CALL  seek              ; llevar el cabezal a la pista
  567.                JNC   fmt_continue      ; no hay problemas
  568. fmt_err_res:   MOV   BX,42h
  569.                MOV   CX,7
  570.                PUSH  AX
  571.                CALL  get_results       ; leer bytes de resultados
  572.                POP   AX
  573.                JMP   fmt_exit          ; error
  574. fmt_continue:  SHL   DH,2
  575.                OR    DH,DL             ; DH = byte 1 del comando
  576.                MOV   DL,0CDh           ; comando de formateo del FDC
  577.                PUSH  DS
  578.                XOR   SI,SI
  579.                MOV   DS,SI
  580.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  581.                PUSH  AX
  582.                MOV   AX,[SI+7]         ; GAP formateo/byte de relleno
  583.                MOV   [BP],AX           ; preservarlo
  584.                POP   AX
  585.                MOV   DI,[SI+3]         ; bytes/sector, sectores/pista
  586.                POP   DS
  587.                MOV   SI,DX             ; primeros bytes del comando
  588.                MOV   CH,6              ; comando de 6 bytes
  589.                AND   BYTE PTR DS:[3Eh],7Fh  ; con espera de IRQ
  590.                CALL  exec_cmd
  591.                JC    fmt_err_res       ; hay error
  592.                MOV   BX,42h
  593.                MOV   CX,7
  594.                CALL  get_results       ; leer bytes de resultados
  595.                JC    fmt_exit
  596.                CALL  get_bios_err      ; obtener código de error
  597. fmt_exit:      MOV   DS:[41h],AH       ; código de error
  598.                CALL  end_io_access
  599.                MOV   AH,DS:[41h]
  600.                OR    AH,AH
  601.                JZ    fmt_end           ; no hay error
  602.                STC
  603. fmt_end:       JMP   main_exit
  604. format_track   ENDP
  605.  
  606. ; ------------ Función 8: Obtener parámetros de disco.
  607.  
  608. get_drv_param  PROC
  609.                CMP   DL,80h
  610.                JB    gdrv_do
  611.                MOV   AH,1              ; función/parámetro incorrecto
  612.                MOV   DS:[41h],AH       ; código de error
  613.                STC
  614.                JMP   main_exit
  615. gdrv_do:       XOR   DI,DI
  616.                XOR   SI,SI
  617.                XOR   DH,DH
  618.                MOV   AL,DS:[10h]       ; hardware instalado
  619.                AND   AL,0C1h           ; nº disqueteras (7-6) y bit
  620.                MOV   DI,2              ; que indica arrancable (0)
  621.                CMP   AL,41h            ; ¿dos disqueteras? (DI=2)
  622.                JE    gdrv_ndisk_ok     ; en efecto
  623.                DEC   DI
  624.                CMP   AL,1              ; ¿una disquetera? (DI=1)
  625.                JE    gdrv_ndisk_ok     ; así es
  626.                JMP   gdrv_res_null     ; no hay disqueteras
  627. gdrv_ndisk_ok: CMP   DL,1
  628.                JBE   gdrv_a_or_b       ; la disquetera es A: o B:
  629.                JMP   gdrv_half_res
  630. gdrv_a_or_b:   CALL  peek_cmos         ; leer tipo de disqueteras
  631.                OR    DL,DL
  632.                JNZ   gdrv_sel
  633.                MOV   CL,4
  634.                SHR   AL,CL             ; dejar disquetera en bits 0-3
  635. gdrv_sel:      AND   AL,0Fh
  636.                JZ    gdrv_media?       ; no existe esa unidad
  637.                CMP   AL,5
  638.                JA    gdrv_media?       ; es mayor de 2.88M
  639.                XOR   AH,AH
  640.                MOV   SI,AX
  641.                MOV   DH,AL
  642.                MOV   BX,90h
  643.                ADD   BL,DL             ; [BX] -> estado físico unidad
  644.                MOV   AL,[BX]
  645.                TEST  AL,10h            ; ¿densidad determinada?
  646.                JNZ   gdrv_calc_p       ; en efecto
  647.                CMP   SI,1              ; ¿unidad de 360K?
  648.                MOV   AL,93h            ; 360K en 360K, 250 Kbps
  649.                JE    gdrv_media_ok
  650.                CMP   SI,2              ; ¿unidad de 1.2M?
  651.                MOV   AL,2              ; "intentando 1.2M"
  652.                JE    gdrv_media_ok
  653.                CMP   SI,3              ; ¿unidad de 720K?
  654.                MOV   AL,97h            ; 720K en 720K, 250 Kbps
  655.                JE    gdrv_media_ok
  656.                CMP   SI,4              ; ¿unidad de 1.44M?
  657.                MOV   AL,7              ; "intentando 1.44M"
  658.                JE    gdrv_media_ok
  659.                MOV   AL,0C7h           ; 2.88M en 2.88M
  660. gdrv_media_ok: MOV   [BX],AL
  661.                JMP   gdrv_calc_p       ; medio físico asignado
  662. gdrv_media?:   MOV   BX,90h
  663.                ADD   BL,DL             ; [BX] -> estado físico unidad
  664.                MOV   AL,[BX]
  665.                TEST  AL,10h            ; ¿densidad determinada?
  666.                JZ    gdrv_eval         ; no
  667.                MOV   AH,AL
  668.                AND   AL,0C0h           ; aislar bits de velocidad
  669.                CMP   AL,80h            ; ¿250 Kbps?
  670.                MOV   SI,2              ; 1.2M
  671.                JNE   gdrv_m144?
  672.                TEST  AH,4
  673.                MOV   SI,1              ; 360K
  674.                JZ    gdrv_calc_p
  675.                MOV   SI,4              ; 1.44M
  676. gdrv_m144?:    TEST  AH,7
  677.                JZ    gdrv_calc_p
  678.                MOV   SI,4              ; 1.44M
  679. gdrv_calc_p:   MOV   BX,DI
  680.                MOV   DI,SI
  681.                DEC   DI
  682.                ADD   DI,DI
  683.                MOV   AX,CS:tab_disksize[DI] ; AL sect/pista, AH pistas
  684.                MOV   r_dh,1                 ; dos cabezales
  685.                MOV   DI,CS:tab_ptr_1e[DI]   ; DI -> tabla parámetros
  686.                PUSH  CS
  687.                POP   ES                ; ES:DI -> parámetros disco
  688. gdrv_set_res:  MOV   r_dl,BL           ; número de unidades
  689.                MOV   r_ch,AH           ; mayor número de cilindro
  690.                MOV   r_cl,AL           ; mayor número de sector
  691.                MOV   r_bl,DH           ; tipo de la unidad
  692.                MOV   r_bh,0
  693.                MOV   r_es,ES           ; ES:DI para la salida
  694.                MOV   r_di,DI
  695.                XOR   AX,AX
  696.                MOV   DS:[41h],AH       ; resultado correcto
  697.                MOV   r_al,AL
  698.                JMP   main_exit
  699. gdrv_res_null: XOR   DI,DI             ; devolver todo a 0
  700. gdrv_half_res: XOR   DH,DH
  701.                XOR   AX,AX
  702.                MOV   ES,AX
  703.                MOV   r_dh,0
  704.                MOV   BX,DI
  705.                XOR   DI,DI
  706.                JMP   gdrv_set_res      ; resultado trivial
  707. gdrv_eval:     MOV   BX,DI
  708.                OR    SI,SI
  709.                JZ    gdrv_res_null     ; no existe la unidad
  710.                CMP   SI,3
  711.                JBE   gdrv_calc_p       ; es de 5¼
  712.                XOR   SI,SI
  713.                JMP   gdrv_res_null
  714. get_drv_param  ENDP
  715.  
  716. ; ------------ Función 18h: Establecer densidad de formateo.
  717.  
  718. set_media_fmt  PROC
  719.                CMP   DL,1
  720.                JBE   setm_do
  721.                MOV   AH,1              ; función/parámetro incorrecto
  722. setm_exit_err: STC
  723.                JMP   main_exit
  724. setm_do:       CALL  get_drive_type    ; obtener tipo disquetera en AL
  725.                JZ    setm_drv_ok
  726. setm_drv_unkn: MOV   AH,0Ch            ; tipo de unidad desconocido
  727.                JMP   setm_exit_err
  728. setm_drv_ok:   XOR   AH,AH
  729.                MOV   DI,AX             ; tipo de unidad
  730.                MOV   DL,r_dl
  731.                MOV   BX,90h
  732.                XOR   DH,DH
  733.                ADD   BX,DX             ; [BX] -> estado físico unidad
  734.                CMP   AL,1              ; ¿360K?
  735.                JNE   setm_not360
  736.                MOV   CX,r_cx           ; restaurar CX
  737.                CMP   CX,2709h          ; ¿40 pistas 9 sectores?
  738.                LEA   SI,t360in360
  739.                JNZ   setm_drv_unkn     ; sólo se permite ese formato
  740.                JMP   setm_360in360
  741. setm_not360:   CMP   AL,3              ; ¿720K?
  742.                JNE   setm_not720
  743.                MOV   CX,r_cx           ; restaurar CX
  744.                CMP   CX,4F09h          ; ¿80 pistas 9 sectores?
  745.                JNE   setm_drv_unkn     ; sólo se permite ese formato
  746.                JMP   setm_setm
  747. setm_not720:   CMP   AL,4              ; ¿1.44M?
  748.                JE    setm_1440
  749.                CMP   AL,2              ; ¿1.2M?
  750.                JE    setm_1200
  751.                CMP   AL,5              ; ¿2.88M?
  752.                JNE   setm_drv_unkn
  753.                MOV   CX,r_cx           ; 2.88M: restaurar CX
  754.                CMP   CX,4F24h          ; ¿80 pistas 36 sectores?
  755.                JE    setm_setm         ; correcto
  756.                CMP   CX,4F12h          ; ¿80 pistas 18 sectores?
  757.                JE    setm_setm         ; correcto
  758.                CMP   CX,4F09h          ; ¿80 pistas 9 sectores?
  759.                JE    setm_setm         ; correcto
  760.                JMP   setm_drv_unkn     ; permitir sólo esos formatos
  761. setm_1200:     MOV   CX,r_cx           ; restaurar CX
  762.                CMP   CX,4F0Fh          ; ¿80 pistas 15 sectores?
  763.                JE    setm_setm         ; correcto
  764.                CMP   CX,2709h          ; ¿80 pistas 9 sectores?
  765.                JNE   setm_drv_unkn     ; permitir sólo esos formatos
  766.                JMP   setm_setm         ; correcto
  767. setm_1440:     MOV   CX,r_cx           ; restaurar CX
  768.                CMP   CX,4F12h          ; ¿80 pistas 18 sectores?
  769.                JE    setm_setm         ; correcto
  770.                CMP   CX,4F09h          ; ¿80 pistas 9 sectores?
  771.                JNE   setm_drv_unkn     ; permitir sólo esos formatos
  772. setm_setm:     MOV   CX,r_cx           ; restaurar CX
  773.                CMP   CX,4F12h          ; ¿80 pistas 18 sectores?
  774.                MOV   AL,17h            ; su byte de medio físico
  775.                LEA   SI,t1440          ; es 1.44M
  776.                MOV   DH,0              ; 500 Kbps
  777.                JZ    setm_m_ok
  778.                CMP   CX,4F09h          ; ¿80 pistas 9 sectores?
  779.                MOV   AL,97h            ; su byte de medio físico
  780.                LEA   SI,t720           ; es 720K
  781.                MOV   DH,2              ; 250 Kbps
  782.                JZ    setm_m_ok
  783.                CMP   CX,4F0Fh          ; ¿80 pistas 15 sectores?
  784.                MOV   AL,15h            ; su byte de medio físico
  785.                LEA   SI,t1200          ; es 1.2M
  786.                MOV   DH,0              ; 500 Kbps
  787.                JZ    setm_m_ok
  788.                CMP   CX,4F24h          ; ¿80 pistas 36 sectores?
  789.                MOV   AL,0D7h           ; su byte de medio físico
  790.                LEA   SI,t2880          ; es 2.88M
  791.                MOV   DH,3              ; 1 Mbps
  792.                JZ    setm_m_ok
  793.                MOV   AL,74h            ; byte medio físico 360K en 1.2
  794.                LEA   SI,t360en1200     ; es 360K en 1.2M
  795.                MOV   DH,1              ; 300 Kbps
  796. setm_m_ok:     MOV   [BX],AL           ; establecer medio físico
  797.                PUSH  DX
  798.                CALL  set_rate          ; velocidad de transferencia DH
  799.                POP   DX
  800.                MOV   AL,[BX]
  801.                AND   AL,0C0h
  802.                AND   BYTE PTR DS:[8Bh],3Fh  ; borrar bits de velocidad
  803.                OR    BYTE PTR DS:[8Bh],AL   ; nueva velocidad
  804.                MOV   r_di,SI
  805.                MOV   r_es,CS              ; retornar tabla parámetros
  806.                MOV   BYTE PTR DS:[41h],0  ; no hay error
  807.                XOR   AH,AH
  808.                JMP   main_exit
  809. setm_360in360: MOV   DH,2                 ; 250 Kbps
  810.                MOV   AL,93h               ; 360K en 360K
  811.                JMP   setm_m_ok
  812. set_media_fmt  ENDP
  813.  
  814. ; ------------ Recalibrar.
  815.  
  816. recalibrate    PROC
  817.                PUSH  SI
  818.                PUSH  CX
  819.                PUSH  DX
  820.                MOV   DH,DL
  821.                MOV   DL,7              ; comando "recalibrate"
  822.                MOV   SI,DX
  823.                MOV   CH,2              ; comando de 2 bytes
  824.                AND   BYTE PTR DS:[3Eh],7Fh  ; con espera de IRQ
  825.                CALL  exec_cmd
  826.                JC    recal_end         ; fallo
  827.                MOV   SI,8              ; "leer estado interrupciones"
  828.                MOV   CH,1              ; comando de 1 byte
  829.                OR    BYTE PTR DS:[3Eh],80h  ; sin espera de IRQ
  830.                CALL  exec_cmd
  831.                JC    recal_end         ; fallo
  832.                MOV   BX,42h
  833.                MOV   CX,2              ; 2 bytes de resultado
  834.                CALL  get_results       ; almacenar resultado
  835.                JC    recal_end         ; fallo
  836.                MOV   BX,42h
  837.                MOV   AH,40h
  838.                MOV   DL,[BX]           ; ST0
  839.                AND   DL,60h
  840.                CMP   DL,60h            ; ¿terminación anormal y
  841.                STC                     ; seek-end?
  842.                JE    recal_end         ; fallo
  843.                POP   DX
  844.                PUSH  DX
  845.                XOR   DH,DH             
  846.                MOV   BX,94H
  847.                ADD   BX,DX
  848.                MOV   BYTE PTR DS:[BX],0  ; cilindro en curso = 0
  849.                MOV   CL,DL
  850.                MOV   DL,1
  851.                SHL   DL,CL
  852.                OR    DS:[3Eh],DL       ; unidad recalibrada
  853.                MOV   CX,43h
  854.                CALL  wait_time         ; retardo de 1 ms
  855.                XOR   AH,AH
  856. recal_end:     MOV   DS:[41h],AH       ; código de error / acierto
  857.                POP   DX
  858.                POP   CX
  859.                POP   SI
  860.                RET
  861. recalibrate    ENDP
  862.  
  863. ; ------------ Llevar el cabezal al cilindro adecuado.
  864.  
  865. seek           PROC
  866.                PUSH  BX
  867.                PUSH  CX
  868.                MOV   AH,DS:[3Eh]       ; estado de recalibración
  869.                MOV   CL,DL
  870.                INC   CL
  871.                SHR   AH,CL
  872.                JC    seek_only
  873.                CALL  recalibrate       ; hay que recalibrar
  874.                JNC   seek_only
  875.                CALL  recalibrate       ; segundo intento
  876.                JNC   seek_only
  877.                JMP   seek_exit
  878. seek_only:     MOV   BX,94H
  879.                XOR   DH,DH
  880.                ADD   BX,DX             ; [BX] -> cilindro actual
  881.                MOV   SI,90h
  882.                ADD   SI,DX             ; [SI] -> estado físico unidad
  883.                MOV   DL,CH
  884.                TEST  BYTE PTR DS:[SI],20h  ; ¿hacer double stepping?
  885.                JZ    seek_cil_ok1
  886.                ADD   DL,DL             ; sí: cilindro=cilindro*2
  887. seek_cil_ok1:  CMP   [BX],DL           ; ¿ya estamos en ese cilindro?
  888.                MOV   DX,r_dx
  889.                JNE   seek_do           ; aún no
  890.                CMP   BYTE PTR DS:[41h],40h  ; ¿hubo "seek error"?
  891.                JE    seek_do
  892.                XOR   AH,AH             ; no, seek innecesario
  893.                JMP   seek_exit
  894. seek_do:       SHL   DH,2
  895.                OR    DH,DL             ; byte 1 del comando seek
  896.                MOV   DL,0FH            ; orden seek
  897.                MOV   SI,DX
  898.                MOV   CL,CH             ; cilindro
  899.                MOV   DX,r_dx           ; unidad / cabezal
  900.                MOV   BX,90h
  901.                XOR   DH,DH
  902.                ADD   BX,DX                 ; [BX] -> estado físico
  903.                TEST  BYTE PTR DS:[BX],20h  ; ¿hacer double stepping?
  904.                JZ    seek_cil_ok2      ; no
  905.                ADD   CL,CL             ; sí: cilindro=cilindro*2
  906. seek_cil_ok2:  MOV   DI,CX
  907.                MOV   CH,3              ; comando de 3 bytes
  908.                AND   BYTE PTR DS:[3Eh],7Fh  ; hay que esperar IRQ
  909.                CALL  exec_cmd
  910.                JNC   seek_ok           ; seek correcto
  911.                JMP   seek_result
  912. seek_ok:       MOV   SI,8              ; "leer estado interrupciones"
  913.                MOV   CH,1              ; comando de 1 byte
  914.                OR    BYTE PTR DS:[3Eh],80h  ; no hay que esperar IRQ
  915.                CALL  exec_cmd
  916.                JC    seek_result       ; fallo
  917.                MOV   BX,42h
  918.                MOV   CX,2
  919.                CALL  get_results       ; leer bytes de resultados
  920.                JC    seek_result
  921.                MOV   BX,42h
  922.                MOV   AH,40h            ; "seek error"
  923.                MOV   DL,[BX]           ; ST0
  924.                AND   DL,60h
  925.                CMP   DL,60h            ; comprobarlo
  926.                STC
  927.                JE    seek_result       ; terminación brusca
  928.                MOV   DX,r_dx           ; restaurar DX
  929.                POP   CX
  930.                PUSH  CX                ; restaurar CX
  931.                MOV   SI,94H
  932.                XOR   DH,DH
  933.                ADD   SI,DX
  934.                MOV   [SI],CH           ; actualizar cilindro actual
  935.                MOV   BX,90h
  936.                ADD   BX,DX             ; [BX] -> estado físico unidad
  937.                MOV   BL,[BX]
  938.                TEST  BL,20h            ; ¿double stepping?
  939.                JZ    seek_cil_ok3
  940.                ADD   [SI],CH           ; pues cilindro*2
  941. seek_cil_ok3:  PUSH  DS
  942.                XOR   SI,SI
  943.                MOV   DS,SI
  944.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  945.                MOV   AL,[SI+9]         ; tiempo estabilización cabezal
  946.                POP   DS
  947.                TEST  BYTE PTR DS:[3Fh],80h  ; ¿operación en curso?
  948.                JZ    seek_wait         ; es lectura o verificación
  949.                OR    AL,AL
  950.                JNZ   seek_wait         ; escritura, cte != 0
  951.                CMP   BL,17h
  952.                MOV   AL,0Fh
  953.                JE    seek_wait         ; 15 ms excepto para 360K
  954.                AND   BL,7
  955.                MOV   AL,14h
  956.                JZ    seek_wait         ; 20 ms para unidades de 360K
  957.                CMP   BL,3
  958.                JE    seek_wait         ; 20 ms para unidades de 360K
  959.                MOV   AL,0Fh            ; 15 ms para demás unidades
  960. seek_wait:     OR    AL,AL
  961.                JZ    seek_wait_end
  962.                MOV   CX,43h
  963.                CALL  wait_time         ; esperar 1 ms...
  964.                DEC   AL
  965.                JMP   seek_wait         ; ...durante AL veces
  966. seek_wait_end: XOR   AH,AH
  967. seek_result:   MOV   DS:[41h],AH       ; resultado
  968. seek_exit:     MOV   DX,r_dx           ; restaurar DX
  969.                POP   CX
  970.                POP   BX
  971.                RET
  972. seek           ENDP
  973.  
  974. ; ------------ Ejecutar operación de E/S a través del FDC.
  975.  
  976. perform_io     PROC
  977.                CALL  seek
  978.                JNC   p_io
  979. p_io_dsk_err:  MOV   AL,0              ; fallo
  980.                PUSH  AX
  981.                MOV   BX,42h
  982.                MOV   CX,7
  983.                CALL  get_results       ; leer bytes de resultados
  984.                POP   AX
  985.                JMP   p_io_exit
  986. p_io:          PUSH  DS                ; preparar bytes comando R/W
  987.                XOR   SI,SI
  988.                MOV   DS,SI
  989.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  990.                MOV   AX,[SI+2]
  991.                AND   AX,0FF00h         ; AH = bytes por sector
  992.                MOV   AL,CL             ; AL = primer sector
  993.                MOV   [BP],AX
  994.                MOV   BX,[SI+4]         ; BL=sectores/pista, BH=GAP R/W
  995.                MOV   CL,[SI+6]         ; CL=longitud de sector (tam=0)
  996.                POP   DS
  997.                MOV   SI,90h
  998.                XOR   DH,DH
  999.                ADD   SI,DX             ; nº sector/tamaño (bytes 4-5)
  1000.                MOV   DL,[SI]           ; estado físico de la unidad
  1001.                AND   DL,7
  1002.                MOV   DH,1Bh            ; GAP R/W para 1.2M/1.44M/2.88M
  1003.                CMP   DL,5
  1004.                JE    p_io_gap_ok       ; 1.2M en 1.2M
  1005.                CMP   BYTE PTR DS:[SI],17h
  1006.                JE    p_io_gap_ok            ; 1.44M
  1007.                CMP   BYTE PTR DS:[SI],0D7h
  1008.                JE    p_io_gap_ok            ; 2.88M
  1009.                MOV   DH,23h            ; GAP R/W para 360K en 1.2M
  1010.                CMP   DL,4
  1011.                JE    p_io_gap_ok       ; 360K en 1.2M
  1012.                MOV   DH,2Ah            ; GAP R/W para demás casos
  1013. p_io_gap_ok:   MOV   BH,DH             ; BX=numsect/GAP (bytes 6-7)
  1014.                MOV   DX,r_dx           ; restaurar DX
  1015.                PUSH  CX
  1016.                MOV   CL,CH             ; cilindro
  1017.                MOV   CH,DH             ; cabezal
  1018.                MOV   DI,CX             ; cabezal/cilindro (bytes 2-3)
  1019.                SHL   DH,2
  1020.                OR    DH,DL             ; byte 1 de comando FDC
  1021.                MOV   DL,0E6h           ; comando leer datos
  1022.                MOV   AX,r_ax           ; orden
  1023.                CMP   AH,3              ; ¿write?
  1024.                JNE   p_io_orden_ok
  1025.                MOV   DL,0C5h           ; comando escribir datos
  1026. p_io_orden_ok: MOV   SI,DX             ; (bytes 0-1 de la orden)
  1027.                POP   CX
  1028.                MOV   CH,9
  1029.                AND   BYTE PTR DS:[3Eh],7Fh  ; esperar interrupción
  1030.                CALL  exec_cmd
  1031.                JNC   p_io_dsk_ok
  1032.                JMP   p_io_dsk_err      ; fallo
  1033. p_io_dsk_ok:   MOV   BX,42h
  1034.                MOV   CX,7
  1035.                CALL  get_results       ; leer bytes de resultados
  1036.                JNC   p_io_res_ok
  1037.                MOV   AL,0
  1038.                JMP   p_io_exit         ; fallo: respetar código error
  1039. p_io_res_ok:   CALL  get_bios_err
  1040. p_io_exit:     MOV   DS:[41h],AH
  1041.                MOV   DX,r_dx           ; restaurar registros
  1042.                MOV   BX,r_bx
  1043.                MOV   CX,r_cx
  1044.                JMP   io_performed      ; continuar operación E/S
  1045. perform_io     ENDP
  1046.  
  1047. ; ------------ Arrancar motor si no lo está.
  1048.  
  1049. motor_on       PROC
  1050.                PUSH  DX
  1051.                PUSH  CX
  1052.                CLI                     ; * evitar reentrada
  1053.                MOV   BYTE PTR DS:[40h],0FFh  ; evitar detención motor
  1054.                AND   BYTE PTR DS:[3Fh],0CFh  ; a 0 bits de disquetera
  1055.                MOV   CH,DL
  1056.                SHL   DL,4
  1057.                OR    DS:[3Fh],DL       ; nueva disquetera seleccionada
  1058.                MOV   CL,CH
  1059.                MOV   DL,DS:[3Fh]       ; estado de motores
  1060.                INC   CL
  1061.                SHR   DL,CL
  1062.                JC    motor_is_on       ; motor ya en marcha
  1063.                MOV   DL,1
  1064.                DEC   CL
  1065.                SHL   DL,CL
  1066.                OR    DS:[3Fh],DL       ; señalizar que está en marcha
  1067.                STI                     ; * fin de la fase crítica
  1068.                MOV   AL,DS:[3Fh]       ; estado de motores
  1069.                ROR   AL,4
  1070.                OR    AL,0CH            ; no resetear, modo DMA
  1071.                MOV   DX,3F2h
  1072.                OUT   DX,AL             ; registro salida digital
  1073.                MOV   AX,90FDh
  1074.                INT   15h               ; permitir multitarea
  1075.                JC    motor_on_end
  1076.                MOV   AH,DS:[3Fh]
  1077.                PUSH  DS
  1078.                PUSH  SI
  1079.                XOR   SI,SI
  1080.                MOV   DS,SI
  1081.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  1082.                MOV   AL,[SI+0Ah]
  1083.                POP   SI                ; AL = tiempo aceleración motor
  1084.                POP   DS                ;      en octavos de segundo
  1085.                SHL   AH,1
  1086.                JNC   motor_on_rv       ; operación read/verify
  1087.                CMP   AL,8
  1088.                JAE   motor_on_wait
  1089.                MOV   AL,8
  1090.                JMP   motor_on_wait     ; escritura: al menos 1 segundo
  1091. motor_on_rv:   CMP   AL,5
  1092.                JAE   motor_on_wait
  1093.                MOV   AL,5              ; read/verify: al menos 625 ms
  1094. motor_on_wait: MOV   CX,208EH
  1095.                CALL  wait_time         ; retardo de unos 125 ms
  1096.                DEC   AL
  1097.                JNZ   motor_on_wait     ; completar retardo
  1098.                JMP   motor_on_end
  1099. motor_is_on:   STI
  1100.                MOV   AL,DS:[3Fh]       ; estado de motores
  1101.                ROR   AL,4
  1102.                OR    AL,0CH            ; no resetear, modo DMA
  1103.                MOV   DX,3F2h
  1104.                OUT   DX,AL             ; seleccionar unidad
  1105. motor_on_end:  POP   CX
  1106.                POP   DX
  1107.                RET
  1108. motor_on       ENDP
  1109.  
  1110. ; ------------ Asignar cuenta para detención motor y devolver en BL
  1111. ;              y AL el próximo número de sector a transferir.
  1112.  
  1113. end_io_access  PROC
  1114.                PUSH  AX
  1115.                PUSH  DS
  1116.                XOR   BX,BX
  1117.                MOV   DS,BX
  1118.                LDS   BX,DWORD PTR DS:[78h]  ; DS:BX -> INT 1Eh
  1119.                MOV   AH,[BX+2]         ; tics hasta detención motor
  1120.                MOV   AL,[BX+4]
  1121.                INC   AL                ; sectores/pista + 1
  1122.                POP   DS
  1123.                MOV   BX,42h
  1124.                CMP   CH,[BX+3]         ; ¿mismo cilindro resultante?
  1125.                JNE   end_io_exit
  1126.                CMP   DH,[BX+4]         ; ¿mismo cabezal resultante?
  1127.                JNE   end_io_exit
  1128.                MOV   AL,[BX+5]         ; número de sector resultante
  1129. end_io_exit:   MOV   DS:[40h],AH       ; tiempo para detención motor
  1130.                MOV   BL,AL             ; último nº sector transferido
  1131.                POP   AX
  1132.                RET
  1133. end_io_access  ENDP
  1134.  
  1135. ; ------------ Leer la línea de cambio de disco y bajarla si está
  1136. ;              activa.
  1137.  
  1138. read_disk_chg  PROC
  1139.                PUSH  CX
  1140.                CALL  get_drive_type    ; obtener tipo disquetera en AL
  1141.                MOV   AH,0
  1142.                JNZ   fallo_cmos
  1143.                DEC   AL
  1144.                JZ    rdchg_set_cod     ; evitar test en 360K
  1145. fallo_cmos:    MOV   AL,[SI]           ; estado físico de la unidad
  1146.                AND   AL,7
  1147.                JZ    rdchg_set_cod     ; evitar test en 360K
  1148.                CMP   AL,3
  1149.                JE    rdchg_set_cod     ; evitar test en 360K
  1150.                MOV   DX,3F7h           ; registro de entrada digital
  1151.                IN    AL,DX             ; leer línea de cambio de disco
  1152.                SHL   AL,1
  1153.                JNC   rdchg_exit        ; no hay cambio de disco
  1154.                AND   BYTE PTR DS:[SI],0EFH  ; medio no determinado
  1155.                CALL  full_init         ; inicialización plena
  1156.                JC    rdchg_exit        ; fallo
  1157.                MOV   DX,r_dx           ; restaurar DX
  1158.                MOV   CH,1
  1159.                CALL  seek              ; cabezal a cilindro 1
  1160.                JC    rdchg_exit
  1161.                MOV   CH,0
  1162.                CALL  seek              ; cabezal a cilindro 0
  1163.                JC    rdchg_exit
  1164.                MOV   AH,6              ; error "disk changed"
  1165.                MOV   DX,3F7h
  1166.                IN    AL,DX             ; leer línea de cambio de disco
  1167.                SHL   AL,1
  1168.                JNC   rdchg_set_cod     ; se ha podido bajar
  1169.                MOV   AH,80h            ; no se pudo: no hay disquete
  1170. rdchg_set_cod: OR    AH,AH
  1171.                JZ    rdchg_exit
  1172.                STC
  1173. rdchg_exit:    MOV   DX,r_dx           ; restaurar DX
  1174.                POP   CX
  1175.                RET
  1176. read_disk_chg  ENDP
  1177.  
  1178. ; ------------ Programar el DMA para efectuar la E/S.
  1179.  
  1180. set_dma        PROC
  1181.                PUSH  AX
  1182.                PUSH  DX
  1183.                CLI
  1184.                MOV   AL,AH
  1185.                OUT   0CH,AL            ; clear first/last flip-flop
  1186.                JCXZ  $+2               ; retardo para E/S
  1187.                JCXZ  $+2
  1188.                OUT   0BH,AL            ; registro de modo del DMA
  1189.                JCXZ  $+2
  1190.                JCXZ  $+2
  1191.                MOV   AL,CL
  1192.                OUT   5,AL
  1193.                JCXZ  $+2
  1194.                JCXZ  $+2
  1195.                MOV   AL,CH
  1196.                OUT   5,AL              ; enviada cuenta de bytes
  1197.                JCXZ  $+2
  1198.                JCXZ  $+2
  1199.                MOV   AL,BL
  1200.                OUT   4,AL
  1201.                JCXZ  $+2
  1202.                JCXZ  $+2
  1203.                MOV   AL,BH
  1204.                OUT   4,AL              ; enviada dirección base
  1205.                JCXZ  $+2
  1206.                JCXZ  $+2
  1207.                MOV   AX,ES
  1208.                OUT   81H,AL            ; registro de página canal 2
  1209.                JCXZ  $+2
  1210.                JCXZ  $+2
  1211.                MOV   AL,2
  1212.                OUT   0AH,AL            ; habilitar canal 2 del DMA
  1213.                STI
  1214.                POP   DX
  1215.                POP   AX
  1216.                RET
  1217. set_dma        ENDP
  1218.  
  1219. ; ------------ Calcular parámetros para programar el DMA.
  1220.  
  1221. eval_dir_DMA   PROC
  1222.                PUSH  CX
  1223.                XOR   AX,AX
  1224.                MOV   CX,ES             ; segmento ES
  1225.                SHL   CX,1              ; desplazar...
  1226.                RCL   AL,1
  1227.                SHL   CX,1
  1228.                RCL   AL,1
  1229.                SHL   CX,1
  1230.                RCL   AL,1
  1231.                SHL   CX,1
  1232.                RCL   AL,1              ; ... AL:CX >> 4
  1233.                MOV   BX,r_bx           ; offset BX
  1234.                ADD   BX,CX
  1235.                ADC   AX,0              ; AX:BX dirección física 20 bit
  1236.                MOV   ES,AX             ; página de DMA
  1237.                POP   CX
  1238.                MOV   AX,CX
  1239.                ADD   AX,BX
  1240.                JNC   eval_dma_ret      ; no cruza frontera de 64k
  1241.                MOV   AH,9              ; "DMA across 64k boundary"
  1242. eval_dma_ret:  RET
  1243. eval_dir_DMA   ENDP
  1244.  
  1245. ; ------------ Enviar comando completo al FDC de CH bytes, contenido
  1246. ;              en SI, DI, [BP], BX y CL (parte baja - alta).
  1247.  
  1248. send_full_cmd  PROC
  1249.                MOV   AX,SI
  1250.                MOV   AH,AL
  1251.                CALL  fdc_write         ; enviar SI-L
  1252.                DEC   CH
  1253.                JBE   send_full_ret     ; acabado (ZF=1) ó error (CF=1)
  1254.                MOV   AX,SI
  1255.                CALL  fdc_write         ; enviar SI-H
  1256.                DEC   CH
  1257.                JBE   send_full_ret
  1258.                MOV   AX,DI
  1259.                MOV   AH,AL
  1260.                CALL  fdc_write         ; enviar DI-L
  1261.                DEC   CH
  1262.                JBE   send_full_ret
  1263.                MOV   AX,DI
  1264.                CALL  fdc_write         ; enviar DI-H
  1265.                DEC   CH
  1266.                JBE   send_full_ret
  1267.                MOV   AX,[BP]
  1268.                MOV   AH,AL
  1269.                CALL  fdc_write         ; enviar [BP]-L
  1270.                DEC   CH
  1271.                JBE   send_full_ret
  1272.                MOV   AX,[BP]
  1273.                CALL  fdc_write         ; enviar [BP]-H
  1274.                DEC   CH
  1275.                JBE   send_full_ret
  1276.                MOV   AH,BL
  1277.                CALL  fdc_write         ; enviar BL
  1278.                DEC   CH
  1279.                JBE   send_full_ret
  1280.                MOV   AH,BH
  1281.                CALL  fdc_write         ; enviar BH
  1282.                DEC   CH
  1283.                JBE   send_full_ret
  1284.                MOV   AH,CL
  1285.                CALL  fdc_write         ; enviar CL
  1286. send_full_ret: RET
  1287. send_full_cmd  ENDP
  1288.  
  1289. ; ------------ Enviar comando al FDC con/sin espera de interrupción.
  1290.  
  1291. exec_cmd       PROC
  1292.                TEST  BYTE PTR DS:[3Eh],80h  ; ¿hay que esperar IRQ?
  1293.                JZ    exec_cmd_irq           ; sí
  1294.                AND   BYTE PTR DS:[3Eh],7Fh  ; no: devolver a 0 bit IRQ
  1295.                CALL  send_full_cmd          ; enviar comando
  1296.                RET
  1297. exec_cmd_irq:  CALL  send_full_cmd          ; enviar comando
  1298.                JC    exec_cmd_ret
  1299.                MOV   AX,9001h
  1300.                INT   15h                    ; permitir multitarea
  1301.                STI
  1302.                JC    exec_cmd_err
  1303.                CALL  wait_int               ; esperar IRQ
  1304.                JNC   exec_cmd_ok
  1305. exec_cmd_err:  MOV   AH,80h                 ; "not ready" (AH=80h)
  1306. exec_cmd_ret:  RET
  1307. exec_cmd_ok:   AND   BYTE PTR DS:[3Eh],7Fh  ; bit IRQ listo para otra
  1308.                XOR   AH,AH                  ; éxito
  1309.                RET
  1310. exec_cmd       ENDP
  1311.  
  1312. ; ------------ Enviar byte al FDC.
  1313.  
  1314. fdc_write      PROC
  1315.                PUSH  CX
  1316.                PUSH  DX
  1317.                MOV   CX,2
  1318.                CALL  wait_time         ; esperar 15-30 µs
  1319.                MOV   DX,3F4h           ; registro de estado
  1320.                PUSH  AX
  1321.                MOV   AH,40h
  1322.                XOR   CX,CX
  1323.                CALL  wait0             ; esperar FDC listo para OUT
  1324.                JC    fdc_wr_fail
  1325.                MOV   AH,80h
  1326.                XOR   CX,CX
  1327.                CALL  wait1
  1328.                JC    fdc_wr_fail       ; error
  1329.                POP   AX
  1330.                MOV   DX,3F5h           ; registro de datos
  1331.                MOV   AL,AH
  1332.                OUT   DX,AL             ; escribir el byte
  1333.                JMP   fdc_wr_ret
  1334. fdc_wr_fail:   POP   AX
  1335.                MOV   AH,80h            ; error "not ready"
  1336. fdc_wr_ret:    POP   DX
  1337.                POP   CX
  1338.                RET
  1339. fdc_write      ENDP
  1340.  
  1341. ; ------------ Leer del FDC CX bytes de resultado en [BX++].
  1342.  
  1343. get_results    PROC
  1344.                PUSH  DX
  1345. get_one_byte:  PUSH  CX
  1346.                CALL  fdc_read
  1347.                POP   CX
  1348.                JC    get_res_ret       ; no hay más bytes que leer
  1349.                MOV   [BX],AL
  1350.                INC   BX
  1351.                LOOP  get_one_byte      ; leer todos los bytes
  1352.                MOV   CX,4
  1353.                CALL  wait_time         ; esperar 45-60 µs
  1354.                MOV   DX,3F4h
  1355.                IN    AL,DX             ; leer registro de estado
  1356.                TEST  AL,10h
  1357.                JZ    get_res_ok        ; el FDC no está ocupado
  1358.                MOV   AH,20h
  1359.                STC                     ; lo estaba: "bad NEC"
  1360.                JMP   get_res_ret
  1361. get_res_ok:    XOR   AH,AH             ; operación correcta
  1362. get_res_ret:   POP   DX
  1363.                RET
  1364. get_results    ENDP
  1365.  
  1366. ; ------------ Leer byte del FDC.
  1367.  
  1368. fdc_read       PROC
  1369.                PUSH  DX
  1370.                MOV   CX,3
  1371.                CALL  wait_time         ; esperar 30-45 µs
  1372.                MOV   DX,3F4h           ; registro de estado
  1373.                MOV   AH,80h
  1374.                XOR   CX,CX
  1375.                CALL  wait1             ; esperar FDC listo para E/S
  1376.                MOV   AH,80h
  1377.                JC    fdc_read_end      ; error "not ready" (AH=80h)
  1378.                IN    AL,DX
  1379.                TEST  AL,40h            ; ¿el FDC quiere dar un byte?
  1380.                JNZ   fdc_read_ok
  1381.                MOV   AH,20H            ; no: error "bad NEC" (AH=20h)
  1382.                STC
  1383.                JMP   fdc_read_end
  1384. fdc_read_ok:   JCXZ  $+2               ; retardo para E/S
  1385.                JCXZ  $+2
  1386.                MOV   DX,3F5h           ; registro de datos
  1387.                IN    AL,DX             ; leer el byte
  1388. fdc_read_end:  POP   DX
  1389.                RET
  1390. fdc_read       ENDP
  1391.  
  1392. ; ------------ Obtener código de error de la BIOS.
  1393.  
  1394. get_bios_err   PROC
  1395.                MOV   BX,42h            ; área de resultados del FDC
  1396.                MOV   BX,[BX]
  1397.                TEST  BL,0C0h           ; ¿que tal ST0?
  1398.                MOV   AH,0
  1399.                JZ    bios_err_det      ; ¡perfecto!
  1400.                TEST  BL,40h            ; ¿terminación brusca/anormal?
  1401.                MOV   AH,20H            ; "bad NEC"
  1402.                JZ    bios_err_det
  1403.                TEST  BH,1              ; ¿falta marca de direcciones?
  1404.                MOV   AH,2              ; "address mark not found"
  1405.                JNZ   bios_err_det
  1406.                TEST  BH,2              ; ¿protegido contra escritura?
  1407.                MOV   AH,3              ; "write-protect error"
  1408.                JNZ   bios_err_det
  1409.                TEST  BH,4              ; ¿sector no encontrado?
  1410.                MOV   AH,4              ; "sector not found"
  1411.                JNZ   bios_err_det
  1412.                TEST  BH,10H            ; ¿DMA no atendido a tiempo?
  1413.                MOV   AH,8              ; "DMA overrun"
  1414.                JNZ   bios_err_det
  1415.                TEST  BH,20H            ; ¿falla el CRC?
  1416.                MOV   AH,10H            ; "CRC error"
  1417.                JNZ   bios_err_det
  1418.                TEST  BH,80h            ; ¿acceso fuera de la pista?
  1419.                MOV   AH,4              ; "sector not found"
  1420.                JNZ   bios_err_det
  1421.                MOV   AH,20H            ; otro error: "bad NEC"
  1422. bios_err_det:  RET
  1423. get_bios_err   ENDP
  1424.  
  1425. ; ------------ Reinicializar la controladora de disquetes.
  1426.  
  1427. init_fdc       PROC
  1428.                CALL  reset_disk        ; resetear FDC
  1429.                JC    init_fin          ; fallo al resetear
  1430.                MOV   DX,3F4h           ; registro de estado del FDC
  1431.                IN    AL,DX
  1432.                TEST  AL,80h
  1433.                JZ    init_otravez      ; el FDC no está listo
  1434.                TEST  AL,40h
  1435.                JZ    init_bien         ; el FDC espera datos de la CPU
  1436. init_otravez:  CALL  reset_disk        ; otro intento más
  1437.                MOV   DX,3F4h
  1438.                IN    AL,DX
  1439.                TEST  AL,80h
  1440.                JZ    init_mal          ; nada, que no tira
  1441.                TEST  AL,40h
  1442.                JZ    init_bien         ; bueno, ya despierta
  1443. init_mal:      MOV   AH,20h            ; fallo de la controladora
  1444.                STC
  1445.                JMP   init_fin
  1446. init_bien:     MOV   AH,8              ; "leer estado interrupciones"
  1447.                CALL  fdc_write         ; enviar comando
  1448.                JC    init_fin          ; fallo
  1449.                CALL  fdc_read          ; leer ST0
  1450.                JC    init_fin          ; fallo
  1451.                MOV   DS:[42h],AL       ; guardar ST0
  1452.                PUSH  AX
  1453.                CALL  fdc_read          ; leer cilindro actual
  1454.                MOV   DS:[42h+1],AL     ; guardarlo
  1455.                POP   CX
  1456.                JC    init_fin          ; fallo
  1457.                AND   CL,0C0h
  1458.                CMP   CL,0C0h           ; ¿terminación anormal?
  1459.                JNE   init_mal          ; no es terminación anormal
  1460.                XOR   AH,AH             ; ok: el FDC detecta el fallo
  1461. init_fin:      JMP   fdc_init
  1462. init_fdc       ENDP
  1463.  
  1464. ; ------------ Resetear el FDC.
  1465.  
  1466. reset_disk     PROC
  1467.                CLI
  1468.                AND   BYTE PTR DS:[3Fh],7Fh  ; operación R/V
  1469.                AND   BYTE PTR DS:[3Eh],7Fh  ; borrar bit IRQ
  1470.                MOV   AL,DS:[3Fh]
  1471.                ROL   AL,4              ; bits 7-4: motores
  1472.                AND   AL,0FBH           ; bits 3-0: unidad
  1473.                OR    AL,8              ; interrupciones ON + reset
  1474.                MOV   DX,3F2h
  1475.                OUT   DX,AL             ; hacer reset
  1476.                MOV   CX,3
  1477.                CALL  wait_time         ; retardo de 30-45µs
  1478.                OR    AL,0CH
  1479.                OUT   DX,AL             ; fin del reset
  1480.                MOV   AX,9001h
  1481.                INT   15h               ; facilitar multitarea
  1482.                STI
  1483.                JC    fin_wait          ; error
  1484.                CALL  wait_int          ; esperar interrupción de disco
  1485. fin_wait:      MOV   AH,80h            ; "unidad no preparada"
  1486.                JC    exit_reset        ; hay error
  1487.                AND   BYTE PTR DS:[3Eh],7Fh  ; borrar bit IRQ
  1488.                XOR   AH,AH                  ; no hay error
  1489. exit_reset:    RET
  1490. reset_disk     ENDP
  1491.  
  1492. ; ------------ Enviar comando specify obtenido de INT 1Eh al FDC.
  1493.  
  1494. send_specify   PROC
  1495.                PUSH  DS
  1496.                XOR   BX,BX
  1497.                MOV   DS,BX
  1498.                LDS   BX,DWORD PTR DS:[78h]  ; DS:BX -> INT 1Eh
  1499.                MOV   AL,3                   ; comando specify del FDC
  1500.                MOV   AH,[BX]           ; byte 0 del comando specify
  1501.                MOV   SI,AX
  1502.                MOV   AL,[BX+1]         ; byte 1 del comando specify
  1503.                MOV   DI,AX
  1504.                MOV   CH,3              ; orden de 3 bytes (SI, DI-L)
  1505.                POP   DS
  1506.                OR    BYTE PTR DS:[3Eh],80h  ; no esperar IRQ
  1507.                CALL  exec_cmd           ; mandar specify al FDC
  1508.                JMP   specify_sent
  1509. send_specify   ENDP
  1510.  
  1511. ; ------------ Esperar una interrupción de disco durante 2 segundos.
  1512.  
  1513. wait_int       PROC
  1514.                MOV   BX,3Eh            ; variable con flag de INT
  1515.                XOR   CX,CX
  1516.                CALL  wait_event        ; esperar IRQ durante 1 segundo
  1517.                JNC   wait_int_ret
  1518.                XOR   CX,CX
  1519.                CALL  wait_event        ; esperar otro segundo más
  1520. wait_int_ret:  RET
  1521. wait_int       ENDP
  1522.  
  1523. ; ------------ Devolver en AL el tipo de la unidad DL.
  1524.  
  1525. get_drive_type PROC
  1526.                CALL  peek_cmos         ; leer tipo de disqueteras
  1527.                OR    DL,DL
  1528.                JNZ   gdt_unidad_ok
  1529.                SHR   AL,4              ; unidad A:
  1530. gdt_unidad_ok: AND   AL,0Fh
  1531.                CMP   SP,SP             ; ZF=1 -> resultado correcto
  1532.                RET
  1533. get_drive_type ENDP
  1534.  
  1535. ; ------------ Determinar la densidad del disquete.
  1536.  
  1537. detect_media   PROC
  1538.                PUSH  DX
  1539.                PUSH  CX
  1540.                PUSH  BX
  1541.                MOV   BL,r_dl
  1542.                XOR   BH,BH
  1543.                MOV   DL,BL
  1544.                CALL  get_drive_type    ; obtener tipo disquetera en AL
  1545.                MOV   AH,0
  1546.                JZ    dm_fast           ; ha sido posible obtenerlo
  1547.                JMP   dm_slow           ; usar procedimiento lento
  1548. dm_fast:       MOV   BYTE PTR DS:[BX+90h],0  ; estado físico unidad
  1549.                DEC   AX
  1550.                JNZ   dm_es_1200K?
  1551.                MOV   AL,93h            ; 360K: 360K en 360K, 250 Kbps
  1552. dm_try:        PUSH  AX
  1553.                MOV   DH,AL
  1554.                AND   DH,0C0h
  1555.                SHR   DH,6
  1556.                CALL  set_rate          ; velocidad de transferencia DH
  1557.                POP   AX
  1558. dm_result:     MOV   DS:[BX+90h],AL    ; estado físico...
  1559.                TEST  AL,10h            ; ...¿determinado?
  1560.                JZ    dm_fails          ; aún no
  1561.                XOR   AH,AH
  1562.                JMP   dm_exit           ; sí: resultado correcto
  1563.                NOP
  1564. dm_es_1200K?:  DEC   AX
  1565.                JNZ   dm_es_720K?
  1566.                MOV   AL,0              
  1567.                CALL  read_ids          ; 1.2M: 500 kbps
  1568.                MOV   AL,15h            ; indicar 1.2M en 1.2M
  1569.                JNC   dm_result         ; sí funciona
  1570.                MOV   AL,40h
  1571.                MOV   BYTE PTR DS:[BX+90h],2
  1572.                CALL  read_ids          ; probar 300 Kbps
  1573.                MOV   AL,74h            ; indicar 360K en 1.2M
  1574.                JNC   dm_result         ; sí funciona
  1575.                MOV   AL,2              ; indicar "¿1.2M en 1.2M?"
  1576.                JMP   dm_result
  1577. dm_es_720K?:   DEC   AX
  1578.                JNZ   dm_es_1440K?
  1579.                MOV   AL,97h            ; 720K: 250 Kbps
  1580.                JMP   dm_try            ; a probar suerte
  1581. dm_es_1440K?:  DEC   AX
  1582.                JNZ   dm_es_2880K
  1583.                MOV   AL,0
  1584.                CALL  read_ids          ; 1.44M: 500 Kbps
  1585.                MOV   AL,17h            ; indicar 1.44M
  1586.                JNC   dm_result         ; sí funciona
  1587.                MOV   AL,80h
  1588.                CALL  read_ids          ; probar a 250 Kbps
  1589.                MOV   AL,97h            ; indicar 720K
  1590.                JNC   dm_result         ; sí funciona
  1591.                MOV   AL,7              ; indicar "¿1.44M?"
  1592.                JMP   dm_result
  1593. dm_es_2880K:   MOV   AL,0C0h
  1594.                CALL  read_ids          ; 2.88M: 1 Mbps
  1595.                MOV   AL,0D7h           ; indicar 2.88M en 2.88M
  1596.                JNC   dm_result         ; sí funciona
  1597.                MOV   AL,0
  1598.                CALL  read_ids          ; probar 500 Kbps
  1599.                MOV   AL,17h            ; indicar 1.44M
  1600.                JNC   dm_result         ; sí funciona
  1601.                MOV   AL,80h
  1602.                CALL  read_ids          ; probar 250 Kbps
  1603.                MOV   AL,97h            ; indicar 720K
  1604.                JNC   dm_result         ; sí funciona
  1605.                MOV   AL,0C7h           ; indicar "¿2.88M en 2.88M?"
  1606.                JMP   dm_result
  1607. dm_fails:      STC                     ; condición de error
  1608. dm_exit:       MOV   DS:[41h],AH       ; código de error
  1609.                POP   BX
  1610.                POP   CX
  1611.                POP   DX
  1612.                RET
  1613. dm_slow:       MOV   AL,0
  1614.                CALL  read_ids          ; probar 500 Kbps
  1615.                MOV   AL,15h            ; indicar 1.2M en 1.2M
  1616.                JNC   dm_slow_ok        ; sí funciona
  1617.                MOV   AL,40h
  1618.                MOV   BYTE PTR DS:[BX+90h],2
  1619.                CALL  read_ids          ; probar 300 Kbps
  1620.                MOV   AL,74h            ; indicar 360K en 1.2M
  1621.                JNC   dm_slow_ok        ; sí funciona
  1622.                MOV   AL,80h
  1623.                CALL  read_ids          ; probar 250 Kbps
  1624.                MOV   AL,97h            ; indicar 720K ó 360K en 360K
  1625.                JNC   dm_slow_ok        ; sí funciona
  1626.                MOV   AL,0C0h
  1627.                CALL  read_ids          ; probar 1 Mbps
  1628.                MOV   AL,0D7h           ; indicar 2.88M en 2.88M
  1629.                JC    dm_fails          ; no funciona
  1630. dm_slow_ok:    JMP   dm_result
  1631. detect_media   ENDP
  1632.  
  1633. ; ------------ Efectuar una lectura de ID's a velocidad AL (bits 6-7).
  1634.  
  1635. read_ids       PROC
  1636.                PUSH  BX
  1637.                PUSHF
  1638.                CLI
  1639.                MOV   BYTE PTR DS:[40h],0FFh  ; evitar detención motor
  1640.                POPF
  1641.                SHR   AL,6              ; colocar bits de velocidad
  1642.                MOV   DH,AL
  1643.                CALL  set_rate          ; velocidad de transferencia DH
  1644.                MOV   DL,r_dl
  1645.                CALL  recalibrate       ; recalibrar
  1646.                JNC   read_id_try
  1647.                CALL  recalibrate       ; segundo intento
  1648.                JC    read_id_err
  1649. read_id_try:   MOV   CX,3              ; 3 intentos
  1650. read_id_retry: PUSH  CX
  1651.                MOV   DH,DL             ; en el cabezal 0 de la unidad
  1652.                MOV   DL,4Ah            ; comando de leer ID's
  1653.                MOV   SI,DX
  1654.                MOV   DL,DH
  1655.                MOV   CH,2              ; comando de 2 bytes
  1656.                AND   BYTE PTR DS:[3Eh],7Fh  ; esperar interrupción
  1657.                CALL  exec_cmd
  1658.                JC    read_id_fails     ; fallo
  1659.                MOV   BX,42h
  1660.                MOV   CX,7
  1661.                CALL  get_results       ; leer bytes de resultados
  1662.                JC    read_id_fails
  1663.                CALL  get_bios_err      ; obtener código de error
  1664.                POP   CX
  1665.                OR    AH,AH
  1666.                JZ    read_id_ret       ; ya no hay fallo
  1667.                LOOP  read_id_retry     ; reintentar
  1668.                JMP   read_id_err       ; mala suerte
  1669. read_id_fails: POP   CX
  1670. read_id_err:   STC
  1671. read_id_ret:   POP   BX
  1672.                RET
  1673. read_ids       ENDP
  1674.  
  1675. ; ------------ Seleccionar la velocidad de transferencia adecuada.
  1676.  
  1677. select_rate    PROC
  1678.                PUSH  SI
  1679.                MOV   SI,90h
  1680.                XOR   DH,DH
  1681.                ADD   SI,DX             ; [SI] -> estado físico unidad
  1682.                MOV   DH,[SI]           ; estado físico nueva unidad
  1683.                MOV   DL,DS:[8Bh]       ; control del medio físico
  1684.                AND   DX,0C0C0h         ; aislar bits de velocidad
  1685.                CMP   DL,DH             ; ¿velocidad ya seleccionada?
  1686.                JE    selected_rate
  1687.                AND   BYTE PTR DS:[8Bh],3Fh  ; no: borrar la anterior
  1688.                OR    DS:[8Bh],DH            ; indicar la nueva
  1689.                AND   DH,0C0h
  1690.                ROL   DH,2
  1691.                CALL  set_rate          ; nueva velocidad transferencia
  1692. selected_rate: POP   SI
  1693.                MOV   DX,r_dx           ; restaurar DX
  1694.                RET
  1695. select_rate    ENDP
  1696.  
  1697. ; ------------ Establecer la velocidad de transferencia DH.
  1698.  
  1699. set_rate       PROC
  1700.                PUSH  AX
  1701.                MOV   AL,DH
  1702.                MOV   DX,3F7h      ; registro de control del disquete
  1703.                OUT   DX,AL        ; seleccionar velocidad
  1704.                POP   AX
  1705.                RET
  1706. set_rate       ENDP
  1707.  
  1708. ; ------------ Esperar que alguno de los bits a 1 de AH en el
  1709. ;              puerto DX se pongan a 0 en no más de CX 15.09 µs.
  1710.  
  1711. wait0          PROC
  1712.                PUSH  AX
  1713. wait0_do:      IN    AL,DX             ; leer del puerto E/S
  1714.                TEST  AL,AH
  1715.                JZ    wait0_end         ; bit(s) ya a 0
  1716. wait0_delay0:  IN    AL,61h
  1717.                TEST  AL,10h
  1718.                JZ    wait0_delay0      ; esperar 15.09 µs
  1719.                DEC   CX
  1720.                JZ    wait0_fail        ; timeout
  1721.                IN    AL,DX             ; volver a leer del puerto E/S
  1722.                TEST  AL,AH
  1723.                JZ    wait0_end         ; bit(s) ya a 0
  1724. wait0_delay1:  IN    AL,61h
  1725.                TEST  AL,10h
  1726.                JNZ   wait0_delay1      ; esperar 15.09 µs
  1727.                DEC   CX
  1728.                JNZ   wait0_do          ; aún no hay timeout
  1729. wait0_fail:    STC                     ; error de timeout
  1730. wait0_end:     POP   AX
  1731.                RET
  1732. wait0          ENDP
  1733.  
  1734. ; ------------ Esperar que alguno de los bits a 1 de AH en el
  1735. ;              puerto DX se pongan a 1 en no más de CX 15.09 µs.
  1736.  
  1737. wait1          PROC
  1738.                PUSH  AX
  1739. wait1_do:      IN    AL,DX             ; leer del puerto E/S
  1740.                TEST  AL,AH
  1741.                JNZ   wait1_end         ; bit(s) ya a 1
  1742. wait1_delay0:  IN    AL,61h
  1743.                TEST  AL,10h
  1744.                JZ    wait1_delay0      ; esperar 15.09 µs
  1745.                DEC   CX
  1746.                JZ    wait1_fail        ; timeout
  1747.                IN    AL,DX             ; volver a leer del puerto E/S
  1748.                TEST  AL,AH
  1749.                JNZ   wait1_end         ; bit(s) ya a 1
  1750. wait1_delay1:  IN    AL,61h
  1751.                TEST  AL,10h
  1752.                JNZ   wait1_delay1      ; esperar 15.09 µs
  1753.                DEC   CX
  1754.                JNZ   wait1_do          ; aún no hay timeout
  1755. wait1_fail:    STC                     ; error de timeout
  1756. wait1_end:     POP   AX
  1757.                RET
  1758. wait1          ENDP
  1759.  
  1760. ; ------------ Esperar evento durante CX 15.09 µs.
  1761.  
  1762. wait_event     PROC
  1763.                PUSH  AX
  1764. test_int:      TEST  BYTE PTR [BX],80h
  1765.                JNZ   fin_w_event       ; llegó la interrupción
  1766. w_ref1:        IN    AL,61h
  1767.                TEST  AL,10h
  1768.                JZ    w_ref1            ; esperar 15 µs
  1769.                DEC   CX
  1770.                JZ    w_event_none      ; timeout
  1771.                TEST  BYTE PTR [BX],80h
  1772.                JNZ   fin_w_event       ; llegó la interrupción
  1773. w_ref2:        IN    AL,61h
  1774.                TEST  AL,10h
  1775.                JNZ   w_ref2            ; esperar 15 µs
  1776.                DEC   CX
  1777.                JNZ   test_int          ; queda tiempo, esperar más
  1778. w_event_none:  STC                     ; no llegó la interrupción
  1779. fin_w_event:   POP   AX
  1780.                RET
  1781. wait_event     ENDP
  1782.  
  1783. ; ------------ Retardo de CX 15.09 µs aproximadamente.
  1784.  
  1785. wait_time      PROC
  1786.                PUSH  AX
  1787. wait_ref_h:    IN    AL,61h
  1788.                TEST  AL,10h            ; esperar ciclo de refresco
  1789.                JZ    wait_ref_h        ; de memoria (15,09 µs)
  1790.                DEC   CX
  1791.                JZ    wait_time_fin     ; fin de la espera
  1792. wait_ref_l:    IN    AL,61h
  1793.                TEST  AL,10h            ; esperar ciclo de refresco
  1794.                JNZ   wait_ref_l        ; de memoria (15,09 µs)
  1795.                DEC   CX
  1796.                JNZ   wait_ref_h        ; completar espera
  1797. wait_time_fin: POP   AX
  1798.                RET
  1799. wait_time      ENDP
  1800.  
  1801. ; ------------ Simular la lectura del registro 10h de la CMOS, para
  1802. ;              el tipo de las disqueteras.
  1803.  
  1804. peek_cmos      PROC
  1805.                MOV   AL,CS:tipo_drvs   ; nuestro tipo simulado
  1806.                RET
  1807. peek_cmos      ENDP
  1808.  
  1809. ; ------------ Datos.
  1810.  
  1811. tipo_drvs      DB    0    ; tipo de disqueteras (definido al instalar)
  1812.  
  1813.                ; --- Tabla de saltos a las funciones
  1814.  
  1815. tab_jmp        DW    reset, get_status
  1816.                DW    read_wr_verify, read_wr_verify, read_wr_verify
  1817.                DW    format_track, get_drv_param, get_disk_type
  1818.                DW    detect_change, set_type_fmt, set_media_fmt
  1819.  
  1820.                ; --- Tabla de tamaños en sectores y cilindros
  1821.  
  1822. tab_disksize   DW     9 + 39 * 256  ; 360K
  1823.                DW    15 + 79 * 256  ; 1.2M
  1824.                DW     9 + 79 * 256  ; 720K
  1825.                DW    18 + 79 * 256  ; 1.44M
  1826.                DW    36 + 79 * 256  ; 2.88M
  1827.  
  1828.                ; --- Tablas de parámetros de disco (sintaxis INT 1Eh)
  1829.  
  1830. tab_ptr_1e     DW    t360in360, t1200, t720, t1440, t2880
  1831.  
  1832.                ; Bytes de esta tabla, similar a la de INT 1Eh:
  1833.                ;
  1834.                ;     0) byte 1 para 'Specify' (step rate-head unload)
  1835.                ;     1) byte 2 para 'Specify' (head load-modo DMA)
  1836.                ;     2) tics de reloj hasta detención del motor
  1837.                ;     3) tamaño de sector (0-128, 1-256, 2-512, ...)
  1838.                ;     4) sectores por pista
  1839.                ;     5) GAP3 para lectura/escritura
  1840.                ;     6) longitud concreta de sector si tamaño=0
  1841.                ;     7) GAP3 para formateo
  1842.                ;     8) byte de relleno al formatear
  1843.                ;     9) tiempo de estabilización del cabezal en ms
  1844.                ;    10) tiempo aceleración motor, en 1/8 segundos
  1845.                ;    11) número de cilindros menos uno
  1846.                ;    12) velocidad de transferencia (en bits 6-7)
  1847.  
  1848. t360in360      DB    0DFh, 002h, 025h, 002h, 009h   ; 360K en 360K
  1849.                DB    02Ah, 0FFh, 050h, 0F6h, 00Fh
  1850.                DB    008h, 027h, 080h
  1851. t1200          DB    0DFh, 002h, 025h, 002h, 00Fh   ; 1.2M
  1852.                DB    01Bh, 0FFh, 054h, 0F6h, 00Fh
  1853.                DB    008h, 04Fh, 000h
  1854. t720           DB    0DFh, 002h, 025h, 002h, 009h   ; 720K
  1855.                DB    02Ah, 0FFh, 050h, 0F6h, 00Fh
  1856.                DB    008h, 04Fh, 080h
  1857. t1440          DB    0BFh, 002h, 025h, 002h, 012h   ; 1.44M
  1858.                DB    01Bh, 0FFh, 06Ch, 0F6h, 00Fh
  1859.                DB    008h, 04Fh, 000h
  1860. t360en1200     DB    0DFh, 002h, 025h, 002h, 009h   ; 360K en 1.2M
  1861.                DB    02Ah, 0FFh, 050h, 0F6h, 00Fh
  1862.                DB    008h, 027h, 040h
  1863. t2880          DB    0AFh, 002h, 025h, 002h, 024h   ; 2.88M
  1864.                DB    01Bh, 0FFh, 050h, 0F6h, 00Fh
  1865.                DB    008h, 04Fh, 0C0h
  1866.  
  1867.                ; --- Fin del área residente para INT 40h
  1868.  
  1869. fin_residente  EQU   $
  1870.  
  1871. bytes_resid    EQU   fin_residente-ini_residente
  1872.  
  1873. ; ------------ Rutina de gestión de INT 13h (si se necesita). Se llama
  1874. ;              a la INT 40h de manera que esta última no devuelva
  1875. ;              nunca errores de frontera de DMA, para lo que emplea un
  1876. ;              buffer auxiliar de 512 bytes para transferir el sector
  1877. ;              que cruzaría la frontera. En la función de formateo, al
  1878. ;              acceder a la primera pista del disco se invoca primero
  1879. ;              la interrupción original para que el DOS (cargado antes
  1880. ;              que este programa) se entere del cambio de soporte.
  1881.  
  1882. ges_int13      PROC
  1883.                STI
  1884.                CMP   DL,80h
  1885.                JB    floppy
  1886.                JMP   CS:ant_int13
  1887. floppy:        CMP   AH,2
  1888.                JB    floppy_bios
  1889.                CMP   AH,5
  1890.                JE    test_format
  1891.                JB    test_rwv
  1892. floppy_bios:   INT   40h               ; función sin problemas de DMA
  1893.                RETF  2
  1894. ges_int13      ENDP
  1895.  
  1896. test_format    PROC
  1897.                XPUSH <DS, ES, BX>
  1898.                PUSHA
  1899.                PUSH  DX
  1900.                OR    DH,CH
  1901.                POP   DX
  1902.                JNZ   skip_aviso        ; no es pista y cabezal 0
  1903.                PUSHA
  1904.                MOV   AL,1              ; formatear un sector (AH=5)
  1905.                MOV   CH,0
  1906.                MOV   DH,2              ; en cabezal 2 (incorrecto)
  1907.                PUSHF
  1908.                CALL  CS:ant_int13      ; avisar al DOS del nuevo disco
  1909.                POPA
  1910. skip_aviso:    MOV   DI,CS:pbuffer
  1911.                MOV   SI,BX
  1912.                PUSH  ES
  1913.                POP   DS
  1914.                PUSH  CS
  1915.                POP   ES
  1916.                MOV   CX,256
  1917.                CLD
  1918.                REP   MOVSW             ; datos de formateo al buffer
  1919.                POPA                    ; auxiliar
  1920.                MOV   BX,CS:pbuffer
  1921.                INT   40h               ; formateo
  1922.                XPOP  <BX, ES, DS>      ; restaurar registros iniciales
  1923.                RETF  2
  1924. test_format    ENDP
  1925.  
  1926. test_rwv       PROC                    ; para Read/Write/Verify
  1927.                MOV   CS:funcion,AH
  1928.                MOV   CS:nsects,AL
  1929.                XPUSH <SI, DI>
  1930.                XPUSH <AX, DX>
  1931.                MOV   AX,ES
  1932.                MOV   DX,16
  1933.                MUL   DX
  1934.                ADD   AX,BX
  1935.                NEG   AX                ; AX = bytes hasta frontera DMA
  1936.                SHR   AX,9
  1937.                MOV   SI,AX             ; sectores antes frontera
  1938.                XPOP  <DX, AX>
  1939.                PUSH  AX
  1940.                MOV   AH,0
  1941.                MOV   DI,AX
  1942.                POP   AX
  1943.                CMP   SI,DI
  1944.                JBE   trwv_no_sobra
  1945.                MOV   SI,DI
  1946. trwv_no_sobra: SUB   DI,SI             ; sectores+1 tras frontera
  1947.                JZ    trwv_1ok
  1948.                PUSH  CX
  1949.                MOV   CX,SI
  1950.                MOV   AL,CL             ; AL sectores antes de frontera
  1951.                POP   CX
  1952. trwv_1ok:      AND   AL,AL
  1953.                JZ    trwv_1cruza       ; primer sector cruza frontera
  1954.                INT   40h
  1955.                PUSHF
  1956.                JNC   trwv_cont         ; sin fallo E/S
  1957. trwv_exit:     JMP   trwv_ret
  1958. trwv_cont:     AND   DI,DI
  1959.                JZ    trwv_exit         ; se acabó
  1960.                POPF
  1961. trwv_1cruza:   CMP   CS:funcion,3      ; ¿escritura?
  1962.                JNE   trwv_sectdma
  1963.                PUSHA
  1964.                XPUSH <DS, ES>
  1965.                SHL   SI,9              ; sectores transferidos * 512
  1966.                ADD   SI,BX
  1967.                MOV   DI,CS:pbuffer
  1968.                PUSH  ES
  1969.                POP   DS
  1970.                PUSH  CS
  1971.                POP   ES
  1972.                MOV   CX,256
  1973.                CLD
  1974.                REP   MOVSW             ; sector conflictivo a través
  1975.                XPOP  <ES, DS>          ; de buffer auxiliar
  1976.                POPA
  1977. trwv_sectdma:  XPUSH <ES, BX, CX>
  1978.                PUSH  CS
  1979.                POP   ES
  1980.                MOV   BX,CS:pbuffer     ; ES:BX buffer auxiliar
  1981.                MOV   AH,CS:funcion
  1982.                MOV   AL,1              ; un sector
  1983.                ADD   CX,SI             ; nuevo sector inicial
  1984.                INT   40h
  1985.                XPOP  <CX, BX, ES>
  1986.                PUSHF
  1987.                JC    trwv_ret          ; fallo E/S
  1988.                CMP   CS:funcion,2      ; ¿lectura?
  1989.                JNE   trwv_tras?
  1990.                PUSHA
  1991.                XPUSH <DS, ES>
  1992.                SHL   SI,9              ; sectores transferidos * 512
  1993.                MOV   DI,SI
  1994.                ADD   DI,BX
  1995.                MOV   SI,CS:pbuffer
  1996.                PUSH  CS
  1997.                POP   DS
  1998.                MOV   CX,256
  1999.                CLD
  2000.                REP   MOVSW             ; sector conflictivo a través
  2001.                XPOP  <ES, DS>          ; de buffer auxiliar
  2002.                POPA
  2003. trwv_tras?:    MOV   AL,CS:nsects      ; sectores transferidos
  2004.                DEC   DI
  2005.                JZ    trwv_ret          ; no queda nada tras frontera
  2006.                POPF
  2007.                XPUSH <BX, CX>
  2008.                INC   SI
  2009.                ADD   CX,SI             ; nuevo sector inicial
  2010.                SHL   SI,9              ; sectores transferidos * 512
  2011.                ADD   BX,SI
  2012.                MOV   AX,DI             ; sectores restantes
  2013.                MOV   AH,CS:funcion
  2014.                INT   40h
  2015.                XPOP  <CX, BX>
  2016.                MOV   AL,CS:nsects      ; número sectores transferidos
  2017.                PUSHF
  2018. trwv_ret:      POPF
  2019.                XPOP  <DI, SI>
  2020.                RETF  2
  2021. test_rwv       ENDP
  2022.  
  2023. funcion        DB    ?
  2024. nsects         DB    ?
  2025. pbuffer        DW    buffer_io
  2026.  
  2027.                EVEN
  2028. buffer_io      EQU   $
  2029.  
  2030.  
  2031. ; *****************************
  2032. ; *                           *
  2033. ; *   I N S T A L A C I O N   *
  2034. ; *                           *
  2035. ; *****************************
  2036.  
  2037. main           PROC
  2038.                ADD   SP,2              ; quitar dirección de retorno
  2039.                XPUSH <AX, BX, CX, DX, SI, DI, BP, DS, ES>
  2040.                PUSH  CS
  2041.                POP   DS
  2042.                MOV   WORD PTR interrupcion,531Eh  ; opcode PUSH DS,BX
  2043.                MOV   BYTE PTR interrupcion+2,0BBh ; opcode MOV BX,??
  2044.                PUSH  CS
  2045.                POP   ES
  2046.                CALL  inic_general      ; inicializar ciertas variables
  2047.                CALL  analiza_equipo
  2048.                CALL  lee_params        ; parámetros de tipo unidades
  2049.                CALL  set_params        ; actualizar tipo de unidades
  2050.                CALL  valida_drives     ; asegurar que hay unidades
  2051.                TEST  error,0FFFFh
  2052.                JNZ   exit_ins
  2053.                CALL  hay2m?
  2054.                JC    no_2m
  2055.                OR    error,ERR_HAY2M   ; 2M ó 2MX residente
  2056.                JMP   exit_ins
  2057. no_2m:         TEST  accion,I40        ; ¿soporta INT 40h el sistema?
  2058.                JNZ   i40_ok            ; en efecto
  2059.                CALL  set_i13           ; añadir soporte vía INT 13h
  2060. i40_ok:        CALL  mx_get_handle     ; obtener entrada Multiplex
  2061.                JNC   handle_ok
  2062.                OR    error,MX64FULL    ; no quedan entradas
  2063.                JMP   exit_ins
  2064. handle_ok:     MOV   multiplex_id,AH   ; entrada multiplex para 2M
  2065.                CALL  preservar_ints    ; tomar nota de vectores
  2066.                CALL  activar_ints      ; interceptar vectores
  2067.                CALL  set_dev_params    ; establecer tipo unidades DOS
  2068. exit_ins:      CALL  info
  2069.                MOV   BX,pcab_pet_segm
  2070.                MOV   ES,BX
  2071.                MOV   BX,pcab_pet_desp
  2072.                MOV   WORD PTR ES:[BX+3],100h ; indicar retorno correcto
  2073.                MOV   AX,longitud_total
  2074.                MOV   CL,4
  2075.                SHL   AX,CL
  2076.                TEST  error,0FFFFh
  2077.                JZ    exit_ok
  2078.                MOV   WORD PTR ES:[BX+14],0   ; OFFSET 0: no quedará
  2079.                MOV   WORD PTR ES:[BX+16],CS  ; instalado en memoria
  2080.                JMP   exit_interr
  2081. exit_ok:       MOV   WORD PTR ES:[BX+14],AX  ; OFFSET al último byte residente
  2082.                MOV   WORD PTR ES:[BX+16],CS
  2083. exit_interr:   XPOP  <ES, DS, BP, DI, SI, DX, CX, BX, AX>
  2084.                RETF
  2085. main           ENDP
  2086.  
  2087. ; ------------ Leer los parámetros en la línea del CONFIG (ES:BX).
  2088.  
  2089. lee_params     PROC
  2090.                PUSH  ES
  2091.                MOV   BX,pcab_pet_segm
  2092.                MOV   ES,BX
  2093.                MOV   BX,pcab_pet_desp
  2094.                LES   BX,ES:[BX+12h]    ; apuntar a los parámetros
  2095.                CALL  salta_nombre      ; buscar inicio parámetros
  2096. mas_param:     CALL  busca_param       ; saltar delimitadores
  2097.                JC    fin_params        ; no hay parámetros
  2098. otro_drive:    CMP   AX,':a'
  2099.                JE    unidad_ok
  2100.                CMP   AX,':b'           ; admitidas A: y B:
  2101.                JE    unidad_ok
  2102. param_error:   OR    error,ERR_SYNTAX  ; error de sintaxis
  2103.                POP   ES
  2104.                RET
  2105. unidad_ok:     MOV   CL,ES:[BX+2]
  2106.                SUB   CL,'0'            ; tipo de la unidad
  2107.                SUB   AL,'a'
  2108.                MOV   AH,0
  2109.                LEA   DI,tipos_drv
  2110.                ADD   DI,AX
  2111.                CMP   CL,5              ; ¿tipo entre 0 y 5?
  2112.                JA    param_error
  2113.                MOV   [DI],CL           ; definir tipo
  2114.                ADD   BX,3
  2115.                JMP   mas_param         ; próximo parámetro
  2116. fin_params:    POP   ES
  2117.                RET
  2118. lee_params     ENDP
  2119.  
  2120. salta_nombre   PROC                    ; saltar nombre del driver en
  2121.                MOV   AL,ES:[BX]        ; línea de órdenes del CONFIG
  2122.                INC   BX
  2123.                CMP   AL,' '
  2124.                JE    fin_nombre
  2125.                CMP   AL,9
  2126.                JE    fin_nombre
  2127.                CMP   AL,0Dh
  2128.                JE    fin_nombre
  2129.                CMP   AL,0Ah
  2130.                JE    fin_nombre
  2131.                AND   AL,AL
  2132.                JZ    fin_nombre
  2133.                JMP   salta_nombre
  2134. fin_nombre:    RET
  2135. salta_nombre   ENDP
  2136.  
  2137. busca_param    PROC                    ; saltar delimitadores
  2138.                DEC   BX
  2139. p_delimit:     INC   BX
  2140.                MOV   AX,ES:[BX]
  2141.                CMP   AL,' '
  2142.                JE    p_delimit         ; espacio en blanco
  2143.                CMP   AL,9
  2144.                JE    p_delimit         ; tabulador
  2145.                CMP   AL,13
  2146.                JE    p_final           ; CR ó LF indican el final
  2147.                CMP   AL,10
  2148.                JE    p_final
  2149.                OR    AX,"  "           ; poner en minúsculas
  2150.                CLC
  2151.                RET
  2152. p_final:       STC                     ; se acabaron los parámetros
  2153.                RET
  2154. busca_param    ENDP
  2155.  
  2156. ; ------------ Establecer tipo disqueteras (según BIOS o parámetros).
  2157.  
  2158. set_params     PROC
  2159.                PUSH  ES
  2160.                MOV   AL,tipos_drv
  2161.                CMP   AL,-1
  2162.                JNE   ta_calc           ; A: definida por el usuario
  2163.                MOV   AH,8
  2164.                MOV   DL,0
  2165.                INT   13h               ; consultar tipo a la BIOS
  2166.                MOV   AL,BL
  2167.                JNC   ta_val
  2168.                JMP   set_type_exit     ; unidad no existente
  2169. ta_val:        CMP   DL,1
  2170.                JB    set_type_exit
  2171. ta_calc:       CMP   AL,4
  2172.                JBE   ta_set
  2173.                MOV   AL,5              ; 2.88M representado por 5
  2174. ta_set:        AND   tipo_drvs,0Fh
  2175.                MOV   CL,4
  2176.                SHL   AL,CL
  2177.                OR    tipo_drvs,AL      ; tipo A: en nibble alto
  2178.                MOV   AL,tipos_drv+1
  2179.                CMP   AL,-1             ; B: definida por el usuario
  2180.                JNE   tb_calc
  2181.                MOV   AH,8
  2182.                MOV   DL,1
  2183.                INT   13h               ; consultar tipo a la BIOS
  2184.                MOV   AL,BL
  2185.                JC    set_type_exit
  2186.                CMP   DL,2
  2187.                JB    set_type_exit     ; unidad no existente
  2188. tb_calc:       CMP   AL,4
  2189.                JBE   tb_set
  2190.                MOV   AL,5              ; 2.88M representado por 5
  2191. tb_set:        AND   tipo_drvs,0F0h
  2192.                OR    tipo_drvs,AL      ; tipo B: en nibble bajo
  2193. set_type_exit: POP   ES
  2194.                RET
  2195. set_params     ENDP
  2196.  
  2197. ; ------------ Asegurar que se conoce el tipo de las unidades.
  2198.  
  2199. valida_drives  PROC
  2200.                MOV   AL,tipo_drvs
  2201.                AND   AL,0F0h
  2202.                JNZ   drvs_ok
  2203.                OR    error,ERR_MALDRV
  2204. drvs_ok:       RET
  2205. valida_drives  ENDP
  2206.  
  2207. ; ------------ Código ejecutado desde la línea de comandos.
  2208.  
  2209. inicio         PROC  FAR
  2210.                MOV   AX,_PRINCIPAL
  2211.                MOV   DS,AX
  2212.                CALL  param_i?
  2213.                LEA   DX,info_txt
  2214.                CALL  print
  2215.                MOV   AX,4C00h
  2216.                INT   21h                    ; final normal
  2217. inicio         ENDP
  2218.  
  2219.                ; ----- Buscar posible parámetro /I
  2220.  
  2221. param_i?       PROC
  2222.                MOV   DI,80h
  2223.                MOV   CL,ES:[DI]
  2224.                MOV   CH,0
  2225.                INC   CX
  2226. busca_mas:     MOV   DL,OFF
  2227.                JCXZ  ret_bparam
  2228. busca_barra:   INC   DI
  2229.                CMP   BYTE PTR ES:[DI],'/'
  2230.                LOOPNE busca_barra
  2231.                JNE   ret_bparam
  2232.                MOV   AL,ES:[DI+1]
  2233.                OR    AL,32
  2234.                CMP   AL,'i'
  2235.                MOV   DL,ON
  2236.                JE    ret_bparam
  2237.                JMP   busca_mas
  2238. ret_bparam:    MOV   param_i,DL
  2239.                RET
  2240. param_i?       ENDP
  2241.  
  2242. ; ------------ Inicializar ciertas variables.
  2243.  
  2244. inic_general   PROC
  2245.                MOV   AX,(bytes_resid+15)/16
  2246.                MOV   longitud_total,AX ; memoria necesaria
  2247.                MOV   segmento_real,CS  ; anotar segmento del bloque
  2248.                MOV   offset_real,0     ; ídem con el offset
  2249.                RET
  2250. inic_general   ENDP
  2251.  
  2252. ; ------------ Comprobar que la configuración es la adecuada. Para
  2253. ;              saber si la INT 13h de este ordenador acaba llamando a
  2254. ;              la INT 40h, se desvía la INT 40h y se provoca un inocuo
  2255. ;              reset de disquetes vía INT 13h para comprobar si pasa
  2256. ;              por la INT 40h.
  2257.  
  2258. analiza_equipo PROC
  2259.                PUSH  ES
  2260.                CALL  testAT
  2261.                MOV   AX,ERR_TIPOPC
  2262.                JC    cod_err_ok        ; no es AT o superior
  2263.                CALL  test_i40
  2264.                XOR   AX,AX
  2265. cod_err_ok:    OR    error,AX
  2266.                POP   ES
  2267.                RET
  2268. analiza_equipo ENDP
  2269.  
  2270.                ; --- Comprobar si la INT 40h está en uso
  2271.  
  2272. test_i40:      XPUSH <DS, ES>          ; *
  2273.                MOV   AX,3540h
  2274.                INT   21h
  2275.                XPUSH <ES, BX>          ; vector de INT 40h original
  2276.                LEA   DX,i40_aux
  2277.                MOV   AX,2540h
  2278.                INT   21h               ; establecer nueva INT 40h
  2279.                XOR   AX,AX
  2280.                MOV   DL,0
  2281.                INT   13h               ; reset de disco
  2282.                XPOP  <DX, DS>
  2283.                MOV   AX,2540h
  2284.                INT   21h               ; restaurar INT 40h original
  2285.                XPOP  <ES, DS>          ; *
  2286.                RET
  2287.  
  2288. i40_aux        PROC
  2289.                OR    CS:accion,I40     ; sí utilizada INT 40h
  2290.                IRET                    ; desde la INT 13h
  2291. i40_aux        ENDP
  2292.  
  2293.                ; ----- Detectar 286 ó superior.
  2294.  
  2295. testAT         PROC
  2296.                PUSHF
  2297.                POP   AX
  2298.                OR    AH,70h        ; intentar activar bit 12, 13 ó 14
  2299.                PUSH  AX            ; del registro de estado
  2300.                POPF
  2301.                PUSHF
  2302.                POP   AX
  2303.                AND   AH,0F0h
  2304.                CMP   AH,0F0h
  2305.                JE    testedAT
  2306.                STC
  2307. testedAT:      CMC                 ; CF = 0 en AT y 1 en PC/XT
  2308.                RET
  2309. testAT         ENDP
  2310.  
  2311. ; ------------ Desviar también INT 13h ya que en esta máquina el
  2312. ;              gestor de INT 13h no invoca la INT 40h.
  2313.  
  2314. set_i13        PROC
  2315.                INC   offsets_ints      ; usado un vector más
  2316.                INC   BYTE PTR tabla_vectores-1
  2317.                MOV   AX,CS
  2318.                MOV   CX,16
  2319.                MUL   CX
  2320.                ADD   AX,pbuffer
  2321.                ADC   DX,0              ; DX:AX = dirección 20 bits
  2322.                MOV   CX,DX
  2323.                PUSH  AX
  2324.                ADD   AX,511            ; buffer para el mayor sector
  2325.                ADC   DX,0
  2326.                POP   AX
  2327.                CMP   DX,CX
  2328.                JE    dma_ok
  2329.                NEG   AX
  2330.                ADD   pbuffer,AX        ; saltar hasta próxima frontera
  2331.                OR    accion,BUFFERPLUS
  2332. dma_ok:        MOV   AX,pbuffer
  2333.                ADD   AX,512
  2334.                SUB   AX,OFFSET ges_int13
  2335.                ADD   AX,15
  2336.                MOV   CL,4
  2337.                SHR   AX,CL
  2338.                ADD   longitud_total,AX ; es necesaria más memoria
  2339.                RET
  2340. set_i13        ENDP
  2341.  
  2342. ; ------------ Establecer el tipo de las unidades a nivel DOS.
  2343.  
  2344. set_dev_params PROC
  2345.                MOV   AH,30h
  2346.                INT   21h
  2347.                XCHG  AH,AL
  2348.                CMP   AX,314h
  2349.                JB    dev_set           ; DOS < 3.2 -> no soportado
  2350.                MOV   BX,1
  2351. set_otro_dev:  PUSH  BX
  2352.                MOV   AH,8
  2353.                MOV   DL,BL
  2354.                DEC   DL
  2355.                PUSH  BX
  2356.                PUSH  ES
  2357.                INT   13h               ; obtener tipo de la unidad
  2358.                POP   ES
  2359.                MOV   BH,0
  2360.                SHL   BX,1
  2361.                ADD   BX,OFFSET ptr_dev_info
  2362.                MOV   DX,[BX]           ; DS:DX -> tabla de información
  2363.                POP   BX
  2364.                AND   DX,DX
  2365.                JZ    device_set
  2366.                MOV   AX,440Dh          ; IOCTL
  2367.                MOV   CX,0840h
  2368.                INT   21h               ; establecer tipo de soporte
  2369. device_set:    POP   BX
  2370.                INC   BX
  2371.                CMP   BX,2
  2372.                JBE   set_otro_dev
  2373. dev_set:       RET
  2374. set_dev_params ENDP
  2375.  
  2376. ; ------------ Preservar vectores de interrupción previos.
  2377.  
  2378. preservar_INTs PROC
  2379.                XPUSH <ES, DI>
  2380.                LEA   DI,tabla_vectores
  2381.                MOV   CL,[DI-1]
  2382.                MOV   CH,0              ; CX vectores interceptados
  2383. otro_vector:   XPUSH <CX, DI>
  2384.                MOV   AH,35h
  2385.                MOV   AL,[DI]
  2386.                INT   21h               ; obtener vector de INT xx
  2387.                XPOP  <DI, CX>
  2388.                MOV   [DI+1],BX         ; anotar donde apunta
  2389.                MOV   [DI+3],ES
  2390.                ADD   DI,5
  2391.                LOOP  otro_vector       ; repetir con los restantes
  2392.                XPOP  <DI, ES>
  2393.                RET
  2394. preservar_INTs ENDP
  2395.  
  2396. ; ------------ desviar vectores de interrupción a las nuevas rutinas.
  2397.  
  2398. activar_INTs   PROC
  2399.                LEA   SI,offsets_ints
  2400.                MOV   CX,CS:[SI]        ; CX vectores a desviar
  2401.                ADD   SI,2
  2402. desvia_otro:   MOV   AL,CS:[SI]        ; número del vector en curso
  2403.                MOV   DX,CS:[SI+1]      ; obtener offset
  2404.                MOV   AH,25h
  2405.                INT   21h               ; desviar INT xx a DS:DX
  2406.                ADD   SI,3
  2407.                LOOP  desvia_otro
  2408.                RET
  2409. activar_INTs   ENDP
  2410.  
  2411. ; ------------ Buscar entrada no usada en la interrupción Multiplex.
  2412. ;              A la salida, CF=1 si no hay hueco (ya hay 64 programas
  2413. ;              residentes instalados con esta técnica). Si CF=0, se
  2414. ;              devuelve en AH un valor de entrada libre en la INT 2Fh.
  2415.  
  2416. mx_get_handle  PROC
  2417.                MOV   AH,0C0h
  2418. mx_busca_hndl: PUSH  AX
  2419.                MOV   AL,0
  2420.                INT   2Fh
  2421.                CMP   AL,0FFh
  2422.                POP   AX
  2423.                JNE   mx_si_hueco
  2424.                INC   AH
  2425.                JNZ   mx_busca_hndl
  2426.                STC
  2427.                RET
  2428. mx_si_hueco:   CLC
  2429.                RET
  2430. mx_get_handle  ENDP
  2431.  
  2432. ; ------------ Devolver CF=0 si 2M o 2MX están instalados o se ha
  2433. ;              cargado el código 2M en modo SuperBOOT.
  2434.  
  2435. hay2m?         PROC
  2436.                PUSH  ES
  2437.                LEA   SI,id_2m          ; identificación del programa
  2438.                MOV   CX,id_2m_tam
  2439.                MOV   AX,1492h
  2440.                MOV   ES,AX
  2441.                MOV   DI,1992h          ; ES:DI protocolo de búsqueda
  2442.                CALL  mx_find_tsr       ; buscar si está en memoria
  2443.                JNC   hay2m?_ret
  2444.                LEA   SI,id_2mx         ; identificación del programa
  2445.                MOV   CX,id_2mx_tam
  2446.                CALL  mx_find_tsr
  2447.                JNC   hay2m?_ret
  2448.                INT   12h               ; tamaño memoria convencional
  2449.                CMP   AX,640
  2450.                JBE   base_sc_ok
  2451.                MOV   AX,640            ; alguien la ha manipulado
  2452. base_sc_ok:    SUB   AX,5
  2453.                MOV   BX,64
  2454.                MUL   BX                ; AX = segmento de SuperBOOT
  2455.                MOV   CX,6
  2456. scan_boot:     PUSH  CX
  2457.                MOV   ES,AX
  2458.                MOV   DI,6
  2459.                LEA   SI,id_boot
  2460.                MOV   CX,id_boot_tam
  2461.                CLD
  2462.                REP   CMPSB
  2463.                POP   CX
  2464.                JE    hay2m?_ret        ; CF = 0 -> 2M SuperBOOT
  2465.                SUB   AX,1000h
  2466.                LOOP  scan_boot         ; buscar 64K más abajo
  2467.                STC
  2468. hay2m?_ret:    POP   ES
  2469.                RET
  2470. hay2m?         ENDP
  2471.  
  2472. ; ------------ Buscar un TSR por la interrupción Multiplex. A la
  2473. ;              entrada, DS:SI cadena de identificación del programa
  2474. ;              (CX bytes) y ES:DI protocolo de búsqueda (normalmente
  2475. ;              1492h:1992h). A la salida, si el TSR ya está instalado,
  2476. ;              CF=0 y ES:DI apunta a la cadena de identificación del
  2477. ;              mismo. Si no, CF=1 y ningún registro alterado.
  2478.  
  2479. mx_find_tsr    PROC
  2480.                MOV   AH,0C0h
  2481. mx_rep_find:   XPUSH <AX, CX, SI, DS, ES, DI>
  2482.                MOV   AL,0
  2483.                PUSH  CX
  2484.                INT   2Fh
  2485.                POP   CX
  2486.                CMP   AL,0FFh
  2487.                JNE   mx_skip_hndl      ; no hay TSR ahí
  2488.                CLD
  2489.                PUSH  DI
  2490.                REP   CMPSB             ; comparar identificación
  2491.                POP   DI
  2492.                JE    mx_tsr_found      ; programa buscado hallado
  2493. mx_skip_hndl:  XPOP  <DI, ES, DS, SI, CX, AX>
  2494.                INC   AH
  2495.                JNZ   mx_rep_find
  2496.                STC
  2497.                RET
  2498. mx_tsr_found:  ADD   SP,4              ; «sacar» ES y DI de la pila
  2499.                XPOP  <DS, SI, CX, AX>
  2500.                CLC
  2501.                RET
  2502. mx_find_tsr    ENDP
  2503.  
  2504. ; ------------ Informar al usuario.
  2505.  
  2506. info           PROC
  2507.                TEST  error,0FFFFh
  2508.                JZ    info_mas
  2509.                LEA   DX,no_inst_txt
  2510.                CALL  print
  2511.                LEA   DX,mal_cpu_txt
  2512.                TEST  error,ERR_TIPOPC
  2513.                JNZ   print_err
  2514.                LEA   DX,hay2m_txt
  2515.                TEST  error,ERR_HAY2M
  2516.                JNZ   print_err
  2517.                LEA   DX,null_drv_txt
  2518.                TEST  error,ERR_MALDRV
  2519.                JNZ   print_err
  2520.                LEA   DX,err_syntax_txt
  2521.                TEST  error,ERR_SYNTAX
  2522.                JNZ   print_err
  2523.                LEA   DX,err_mx64full
  2524.                TEST  error,MX64FULL
  2525.                JZ    fin_info
  2526. print_err:     CALL  print
  2527.                RET
  2528. info_mas:      LEA   DX,instalado_txt
  2529.                CALL  print
  2530.                CALL  info_drives
  2531.                TEST  accion,BUFFERPLUS
  2532.                JZ    fin_info
  2533.                LEA   DX,dma_cross_txt
  2534.                CALL  print
  2535. fin_info:      RET
  2536. info           ENDP
  2537.  
  2538.                ; --- Informar de las unidades controladas.
  2539.  
  2540. info_drives    PROC
  2541.                MOV   AH,8
  2542.                MOV   DL,0
  2543.                INT   13h
  2544.                JC    info_null         ; no hay información sobre A:
  2545.                AND   BL,BL
  2546.                JZ    info_null
  2547.                CMP   DL,1
  2548.                JB    info_null
  2549.                PUSH  DX
  2550.                MOV   BH,0
  2551.                DEC   BX
  2552.                SHL   BX,1
  2553.                LEA   DX,a_txt          ; "A:"
  2554.                CALL  print
  2555.                MOV   DX,[BX+OFFSET ptr_txt_tipos]  ; su tipo
  2556.                CALL  print
  2557.                POP   DX
  2558.                CMP   DL,2
  2559.                JB    info_exit         ; no hay información sobre B:
  2560.                MOV   AH,8
  2561.                MOV   DL,1
  2562.                INT   13h
  2563.                JC    info_exit
  2564.                AND   BL,BL
  2565.                JZ    info_exit
  2566.                MOV   BH,0
  2567.                DEC   BX
  2568.                SHL   BX,1
  2569.                LEA   DX,b_txt          ; "B:"
  2570.                CALL  print
  2571.                MOV   DX,[BX+OFFSET ptr_txt_tipos]  ; su tipo
  2572.                CALL  print
  2573. info_exit:     LEA   DX,i40_txt
  2574.                TEST  accion,I40
  2575.                JNZ   imodo_ok
  2576.                LEA   DX,i13_txt
  2577. imodo_ok:      CALL  print             ; modo de instalación
  2578.                RET
  2579. info_null:     LEA   DX,null_drv_txt   ; sin indicar tipo de unidades
  2580.                CALL  print
  2581.                RET
  2582. info_drives    ENDP
  2583.  
  2584. ; ------------ Inicializar variable idioma_sp según idioma del país.
  2585.  
  2586. habla_hispana? PROC
  2587.                XPUSH <AX, BX, CX, DX, BP>
  2588.                MOV   AH,30h
  2589.                INT   21h
  2590.                XCHG  AH,AL             ; AX = versión del DOS
  2591.                MOV   BP,AX
  2592.                MOV   idioma_sp,OFF     ; supuesto de habla no hispana
  2593.                CMP   BP,200h
  2594.                JB    habla_ok
  2595.                LEA   DX,buffer_aux
  2596.                MOV   AX,3800h
  2597.                INT   21h               ; obtener información del pais
  2598.                CMP   BP,20Bh
  2599.                JE    habla_ax          ; DOS 2.11: AX cód. telefónico
  2600.                CMP   BP,300h
  2601.                JB    habla_ok          ; 2.x excepto 2.11: mala suerte
  2602.                MOV   AX,BX
  2603. habla_ax:      LEA   BX,paises_sp-2
  2604.                MOV   CX,numpaises_sp
  2605. habla_sp?:     ADD   BX,2
  2606.                CMP   AX,[BX]
  2607.                JE    habla_hispana
  2608.                LOOP  habla_sp?
  2609. habla_ok:      MOV   AL,param_i
  2610.                XOR   idioma_sp,AL      ; considerar parámetro /I
  2611.                XPOP  <BP, DX, CX, BX, AX>
  2612.                RET
  2613. habla_hispana: MOV   idioma_sp,ON      ; país de habla hispana
  2614.                MOV   AL,param_i
  2615.                XOR   idioma_sp,AL      ; considerar parámetro /I
  2616.                XPOP  <BP, DX, CX, BX, AX>
  2617.                RET
  2618. habla_hispana? ENDP
  2619.  
  2620. ; ------------ Imprimir cadena en DS:DX delimitada por un 0 ó un 255.
  2621. ;              Si hay que imprimir en inglés se toma la cadena que va
  2622. ;              después si ésta acaba en 255 (si acaba en 0, no hay
  2623. ;              distinción entre mensaje castellano e inglés).
  2624.  
  2625. print          PROC
  2626.                XPUSH <AX, BX, CX, DX>
  2627. pr_decidir:    CMP   idioma_sp,OFF
  2628.                JE    usar_uk
  2629.                CMP   idioma_sp,ON
  2630.                JE    usar_sp
  2631.                PUSH  DX
  2632.                CALL  habla_hispana?         ; determinar lengua
  2633.                POP   DX
  2634.                JMP   pr_decidir
  2635. usar_uk:       MOV   BX,DX
  2636.                DEC   BX
  2637. usar_uk?:      INC   BX
  2638.                CMP   BYTE PTR [BX],0
  2639.                JE    usar_sp                ; acaba en 0: no traducir
  2640.                CMP   BYTE PTR [BX],255
  2641.                JNE   usar_uk?
  2642.                LEA   DX,[BX+1]              ; acaba en 255: traducir
  2643. usar_sp:       MOV   BX,DX
  2644.                DEC   BX
  2645. print_cad:     INC   BX
  2646.                CMP   BYTE PTR [BX],0
  2647.                JE    prlong_ok
  2648.                CMP   BYTE PTR [BX],255
  2649.                JNE   print_cad              ; calcular longitud
  2650. prlong_ok:     MOV   CX,BX
  2651.                SUB   CX,DX
  2652.                MOV   AH,40h
  2653.                MOV   BX,1
  2654.                INT   21h
  2655.                XPOP  <DX, CX, BX, AX>
  2656.                RET
  2657. print          ENDP
  2658.  
  2659. ; ************ Datos no residentes para la instalación
  2660.  
  2661. ON             EQU   1                 ; constantes booleanas
  2662. OFF            EQU   0
  2663.  
  2664. param_i        DB    OFF               ; a ON si indicado parámetro /I
  2665.  
  2666. tipos_drv      DB    -1                ; tipo de A:
  2667.                DB    -1                ; y de B:
  2668.  
  2669. id_2m          DB    "CiriSOFT:2M:"    ; marcas de presencia de 2M
  2670. id_2m_tam      EQU   $-OFFSET id_2m
  2671. id_2mx         DB    "CiriSOFT:2MX:"
  2672. id_2mx_tam     EQU   $-OFFSET id_2mx
  2673. id_boot        DB    "2M-STV"
  2674. id_boot_tam    EQU   $-OFFSET id_boot
  2675.  
  2676. ERR_TIPOPC     EQU   1                 ; códigos de error
  2677. ERR_HAY2M      EQU   2
  2678. ERR_MALDRV     EQU   4
  2679. ERR_SYNTAX     EQU   8
  2680. MX64FULL       EQU  16
  2681.  
  2682. I40            EQU   1                 ; códigos de acción
  2683. BUFFERPLUS     EQU   2
  2684.  
  2685. offsets_ints   DW    2         ; número de vectores interceptados
  2686.                DB    2Fh       ; tabla de offsets de los vectores
  2687.                DW    ges_int2F ; de interrupción interceptados
  2688.                DB    40h
  2689.                DW    ges_int40
  2690.                DB    13h       ; INT 13h podría usarse
  2691.                DW    ges_int13
  2692.  
  2693. ptr_dev_info   DW    0, i360, i1200, i720, i1440, i2880
  2694.  
  2695. i360           DB    4, 0              ; sectores iguales / tipo 360K
  2696.                DW    0, 40             ; no detecta cambio / nº pistas
  2697.                DB    1                 ; tipo de soporte
  2698.                DW    512               ; BPB: bytes por sector
  2699.                DB    2                 ; BPB: sectores por cluster
  2700.                DW    1                 ; BPB: sectores reservados
  2701.                DB    2                 ; BPB: número de FATs
  2702.                DW    112               ; BPB: entradas en el raíz
  2703.                DW    720               ; BPB: nº total de sectores
  2704.                DB    0FDh              ; BPB: descriptor de medio
  2705.                DW    2                 ; BPB: sectores por FAT
  2706.                DW    9, 2              ; BPB: sectores pista / cabezas
  2707.                DB    14 DUP (0)        ; BPB: restantes campos
  2708. i1200          DB    4, 1              ; sectores iguales / tipo 1.2M
  2709.                DW    2, 80             ; detecta cambio / nº pistas
  2710.                DB    0                 ; tipo de soporte
  2711.                DW    512               ; BPB: bytes por sector
  2712.                DB    1                 ; BPB: sectores por cluster
  2713.                DW    1                 ; BPB: sectores reservados
  2714.                DB    2                 ; BPB: número de FATs
  2715.                DW    224               ; BPB: entradas en el raíz
  2716.                DW    2400              ; BPB: nº total de sectores
  2717.                DB    0F9h              ; BPB: descriptor de medio
  2718.                DW    7                 ; BPB: sectores por FAT
  2719.                DW    15, 2             ; BPB: sectores pista / cabezas
  2720.                DB    14 DUP (0)        ; BPB: restantes campos
  2721. i720           DB    4, 2              ; sectores iguales / tipo 720K
  2722.                DW    0, 80             ; no detecta cambio / nº pistas
  2723.                DB    0                 ; tipo de soporte
  2724.                DW    512               ; BPB: bytes por sector
  2725.                DB    2                 ; BPB: sectores por cluster
  2726.                DW    1                 ; BPB: sectores reservados
  2727.                DB    2                 ; BPB: número de FATs
  2728.                DW    112               ; BPB: entradas en el raíz
  2729.                DW    1440              ; BPB: nº total de sectores
  2730.                DB    0F9h              ; BPB: descriptor de medio
  2731.                DW    3                 ; BPB: sectores por FAT
  2732.                DW    9, 2              ; BPB: sectores pista / cabezas
  2733.                DB    14 DUP (0)        ; BPB: restantes campos
  2734. i1440          DB    4, 7              ; sectores iguales / tipo 1.44M
  2735.                DW    2, 80             ; detecta cambio / nº pistas
  2736.                DB    0                 ; tipo de soporte
  2737.                DW    512               ; BPB: bytes por sector
  2738.                DB    1                 ; BPB: sectores por cluster
  2739.                DW    1                 ; BPB: sectores reservados
  2740.                DB    2                 ; BPB: número de FATs
  2741.                DW    224               ; BPB: entradas en el raíz
  2742.                DW    2880              ; BPB: nº total de sectores
  2743.                DB    0F0h              ; BPB: descriptor de medio
  2744.                DW    9                 ; BPB: sectores por FAT
  2745.                DW    18, 2             ; BPB: sectores pista / cabezas
  2746.                DB    14 DUP (0)        ; BPB: restantes campos
  2747. i2880          DB    4, 9              ; sectores iguales / tipo 2.88M
  2748.                DW    2, 80             ; detecta cambio / nº pistas
  2749.                DB    0                 ; tipo de soporte
  2750.                DW    512               ; BPB: bytes por sector
  2751.                DB    2                 ; BPB: sectores por cluster
  2752.                DW    1                 ; BPB: sectores reservados
  2753.                DB    2                 ; BPB: número de FATs
  2754.                DW    224               ; BPB: entradas en el raíz
  2755.                DW    5760              ; BPB: nº total de sectores
  2756.                DB    0F0h              ; BPB: descriptor de medio
  2757.                DW    9                 ; BPB: sectores por FAT
  2758.                DW    36, 2             ; BPB: sectores pista / cabezas
  2759.                DB    14 DUP (0)        ; BPB: restantes campos
  2760.  
  2761. accion         DW    0
  2762. error          DW    0
  2763. idioma_sp      DB    5Ah       ; ni en ON ni en OFF al principio
  2764.  
  2765.                ; --- Código telefónico de países de
  2766.                ;     habla hispana (mucha o poca).
  2767.  
  2768. paises_sp      DW    54                ; Argentina
  2769.                DW    591               ; Bolivia
  2770.                DW    57                ; Colombia
  2771.                DW    506               ; Costa Rica
  2772.                DW    56                ; Chile
  2773.                DW    593               ; Ecuador
  2774.                DW    503               ; El Salvador
  2775.                DW    34                ; España
  2776.                DW    63                ; Filipinas
  2777.                DW    502               ; Guatemala
  2778.                DW    504               ; Honduras
  2779.                DW    212               ; Marruecos
  2780.                DW    52                ; México
  2781.                DW    505               ; Nicaragua
  2782.                DW    507               ; Panamá
  2783.                DW    595               ; Paraguay
  2784.                DW    51                ; Perú
  2785.                DW    80                ; Puerto Rico
  2786.                DW    508               ; República Dominicana
  2787.                DW    598               ; Uruguay
  2788.                DW    58                ; Venezuela
  2789.                DW    3                 ; genérico latinoamérica
  2790. numpaises_sp   EQU   ($-OFFSET paises_sp)/2
  2791.  
  2792. ; ------------ Texto.
  2793.  
  2794. instalado_txt  DB    13,10,"2M-ABIOS 1.2 instalado en ",255
  2795.                DB    13,10,"2M-ABIOS 1.2 installed on ",0
  2796.  
  2797. a_txt          DB    "A:",0
  2798. b_txt          DB    " y B:",255," and B:",0
  2799. ptr_txt_tipos  DW    d360, d1200, d720, d1440, d2880
  2800. d360           DB    "360K",0
  2801. d1200          DB    "1.2M",0
  2802. d720           DB    "720K",0
  2803. d1440          DB    "1.44M",0
  2804. d2880          DB    "2.88M",0
  2805. i40_txt        DB    "  [INT 40h]",13,10,0
  2806. i13_txt        DB    "  [INT 13h]",13,10,0
  2807.  
  2808. no_inst_txt    DB    13,10,"2M-ABIOS 1.2 *NO* instalado.",13,10,255
  2809.                DB    13,10,"2M-ABIOS 1.2 *NOT* installed.",13,10,0
  2810.  
  2811. mal_cpu_txt    DB    "  + Error: necesario equipo AT ó superior. Utilice 2M-XBIOS en este equipo.",13,10,255
  2812.                DB    "  + Error: needs AT or upper system. Try 2M-XBIOS on this system.",13,10,0
  2813.  
  2814. hay2m_txt      DB    "  + Error: 2M-ABIOS debe instalarse *ANTES* de 2M (y nunca en SuperBOOT).",13,10,255
  2815.                DB    "  + Error: 2M-ABIOS must be installed *BEFORE* 2M (and never in SuperBOOT).",13,10,0
  2816.  
  2817. null_drv_txt   DB    "  + Utilice los parámetros para indicar expresamente el tipo de las unidades.",13,10,255
  2818.                DB    "  + Please use the switches to set the correct diskette drives type.",13,10,0
  2819.  
  2820. err_syntax_txt DB    "  + Error de sintaxis: ejecútelo desde el símbolo DOS para obtener ayuda.",13,10,255
  2821.                DB    "  + Syntax error: execute from DOS command line to obtain help.",13,10,0
  2822.  
  2823. err_mx64full   DB    "  + Error: Ya hay 64 programas residentes con la misma técnica.",13,10,7,255
  2824.                DB    "  + Error: There are already 64 TSR's with the same technique.",13,10,7,0
  2825.  
  2826. dma_cross_txt  DB    "    - Nota: El buffer de E/S cruzaba una frontera de DMA y fue ampliado.",13,10
  2827.                DB    "            Cambie la ubicación en memoria si desea ahorrar unos bytes.",13,10,255
  2828.                DB    "    - Note: I/O buffer has been extended because it crosses a DMA boundary.",13,10
  2829.                DB    "            Modify the memory location of 2M-ABIOS to save a little memory.",13,10,0
  2830.  
  2831. info_txt       LABEL BYTE
  2832.                DB    13,10
  2833.                DB    "           2M-ABIOS 1.2  -  (c) Mayo 1994 Ciriaco García de Celis.",13,10
  2834.                DB    "  C/Renedo, 2, 4-C; 47005 Valladolid (España) - ciri@gui.uva.es - 2:341/21.8",13,10,10
  2835.                DB    "               Sintaxis:  DEVICE=2M-ABIOS.EXE [A:tipo [B:tipo]]",13,10,10
  2836.                DB    "    Algunos ordenadores poseen una BIOS antigua o con un diseño propio poco",13,10
  2837.                DB    "  compatible en el control de disco. En estas máquinas 2M y otros programas",13,10
  2838.                DB    "  de acceso a bajo nivel pueden fallar.  En dichos casos, conviene instalar",13,10
  2839.                DB    "  esta utilidad antes que 2M,  y en general que cualquier otro software que",13,10
  2840.                DB    "  acceda al subsistema de disco. Este programa es sólo para máquinas AT.",13,10,10
  2841.                DB    "    2M-ABIOS  actualiza el soporte de disco flexible a la última tecnología",13,10
  2842.                DB    "  de las BIOS AMI de 1993.  Si con 2M-ABIOS instalado 2M no opera de manera",13,10
  2843.                DB    "  totalmente correcta y en su máquina no está instalado algún otro software",13,10
  2844.                DB    "  de disco incompatible con 2M, entonces su ordenador no es 100% compatible",13,10
  2845.                DB    "  hardware con el estándar;  esto es particularmente cierto si con 2M-ABIOS",13,10
  2846.                DB    "  instalado no se reconocen siquiera los discos estándar del DOS.",13,10,10
  2847.                DB    "    Este programa ocupa 3.4-4.2 Kb de RAM, y contiene una emulación al 100%",13,10
  2848.                DB    "  del eficaz código de control de disco de las BIOS AMI,  relevando así por",13,10
  2849.                DB    "  completo de esta tarea a la BIOS del sistema.  Generalmente no hará falta",13,10
  2850.                DB    "  indicar el tipo (0:no hay, 1:360K, 2:1.2M, 3:720K, 4:1.44M, 5:2.88M). AMI",13,10
  2851.                DB    "  es marca registrada de American Megatrends Inc.",13,10
  2852.                DB    255
  2853.                DB    13,10,10
  2854.                DB    "           2M-ABIOS 1.2  -  (c) Mayo 1994 Ciriaco García de Celis.",13,10
  2855.                DB    "  C/Renedo, 2, 4-C; 47005 Valladolid (Spain) - ciri@gui.uva.es - 2:341/21.8",13,10,10
  2856.                DB    "               Syntax:  DEVICE=2M-ABIOS.EXE [A:type [B:type]]",13,10,10
  2857.                DB    "    Some computers have an old BIOS or a BIOS built with a peculiar design,",13,10
  2858.                DB    "  few compatible in disk operation. In those systems 2M and other low-level",13,10
  2859.                DB    "  software can fails. In these cases you can install 2M-ABIOS before 2M and",13,10
  2860.                DB    "  before any other disk  TSR  software.  This program is only for use on AT",13,10
  2861.                DB    "  computer systems.",13,10,10
  2862.                DB    "    2M-ABIOS upgrades floppy-disk support to last AMI BIOS 1993 technology.",13,10
  2863.                DB    "  If 2M-ABIOS is installed,  and 2M continues not working full correctly on",13,10
  2864.                DB    "  your computer, and is not installed in the system any other disk software",13,10
  2865.                DB    "  incompatible with 2M,  this probably means that your computer is not 100%",13,10
  2866.                DB    "  hardware compatible with the standard AT;  this is specially true if only",13,10
  2867.                DB    "  2M-ABIOS is installed and DOS standard diskettes don't work.",13,10,10
  2868.                DB    "    This program takes 3.4-4.2 Kb of RAM,  and provides a full emulation of",13,10
  2869.                DB    "  the effective disk control management of AMI BIOS,  absolutely overriding",13,10
  2870.                DB    "  your native BIOS in this job. Usually you do not need to select the drive",13,10
  2871.                DB    "  type (0:not present, 1:360K, 2:1.2M, 3:720K, 4:1.44M, 5:2.88M).  AMI is a",13,10
  2872.                DB    "  registered trademark of American Megatrends Inc.",13,10
  2873.                DB    0
  2874.  
  2875. buffer_aux     DB    64 DUP (0)   ; buffer para alguna función del DOS
  2876.  
  2877. _PRINCIPAL     ENDS
  2878.  
  2879. _PILA          SEGMENT STACK 'STACK'
  2880.                DB    1024 DUP (?)      ; 1 Kb de pila es suficiente
  2881. _PILA          ENDS
  2882.  
  2883.                END   inicio
  2884.